﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Text;
using System.Windows.Forms;
using RaGE.Properties;

namespace RaGE
{
    public partial class MainWindow
    {
        private void ClearParams()
        {
            groupBox_ProcParams.Text = Resources.ProcedureParameters;
            label_Param1.Text = Resources.NULL;
            label_Param2.Text = Resources.NULL;
            label_Param3.Text = Resources.NULL;
            label_Param4.Text = Resources.NULL;
            label_Param5.Text = Resources.NULL;
            label_Param6.Text = Resources.NULL;
            label_Param7.Text = Resources.NULL;
            label_Param1.Text = Resources.NULL;
            textBox_Param1.Text = "";
            textBox_Param2.Text = "";
            textBox_Param3.Text = "";
            textBox_Param4.Text = "";
            textBox_Param5.Text = "";
            textBox_Param6.Text = "";
            textBox_Param7.Text = "";
            textBox_ParamTarget.Text = "";
        }

        private static Condition LoadCondition(BinaryReader br)
        {
            var condition = new Condition();
            condition.OperID = br.ReadInt32();
            condition.ArgBytes = br.ReadInt32();
            condition.Value = br.ReadBytes(condition.ArgBytes);
            condition.ConditionType = br.ReadInt32();

            if (condition.ConditionType == 1)
            {
                condition.ConditionLeft = LoadCondition(br);
                condition.SubNodeL = br.ReadInt32();
                condition.ConditionRight = LoadCondition(br);
                condition.SubNodeR = br.ReadInt32();
            }

            if (condition.ConditionType == 2)
            {
                condition.ConditionRight = LoadCondition(br);
                condition.SubNodeL = br.ReadInt32();
            }
            return condition;
        }

        //*************************************************************
        //               Jade Dynasty Specific
        //*************************************************************

        private object[] JDReadParameters(int type, BinaryReader br, int ver)
        {
            switch (type)
            {
                // Type 0 - Attack(int unk)
                case 0:
                    return new object[] { br.ReadInt32() };

                // Type 1 - Cast_Skill(int skill_id, int skill_lvl)
                case 1:
                    return new object[] { br.ReadInt32(), br.ReadInt32() };

                // Type 2 - Broadcast_Message(int byteCount, byte[] message)
                case 2:
                    var byteCount = br.ReadInt32();
                    return new object[] { byteCount, br.ReadBytes(byteCount) };

                // Type 3 - Reset_Aggro()
                case 3:
                    return new object[0];

                // Type 4 - Exec_ActionSet(int actionset_id)
                case 4:
                    return new object[] { br.ReadInt32() };

                // Type 5 - Disable_ActionSet(int actionset_id)
                case 5:
                    return new object[] { br.ReadInt32() };

                // Type 6 - Enable_ActionSet(int actionset_id)
                case 6:
                    return new object[] { br.ReadInt32() };

                // Type 7 - Create_Timer(int timerID, int delay, int cycles)
                case 7:
                    return new object[] { br.ReadInt32(), br.ReadInt32(), br.ReadInt32() };

                // Type 8 - Delete_Timer(int timerID)
                case 8:
                    return new object[] { br.ReadInt32() };

                // Type 9 - Flee()
                case 9:
                    return new object[0];

                // Type 10 - Be_Taunted()
                case 10:
                    return new object[0];

                // Type 11 - Unknown11()
                case 11:
                    return new object[0];

                // Type 12 - Fade_Aggro()
                case 12:
                    return new object[0];

                // Type 13 - Unknown13()
                case 13:
                    return new object[0];

                // Type 14 - Trigger(int triggerID, int ctrlParam)
                case 14:
                    return new object[] { br.ReadInt32(), br.ReadInt32() };

                // Type 15 - Summon_Mob(int elementsID, int timeInterval, int calls, int Survival, string mobName, int refreshRange, int unknown)
                case 15:
                    return new object[] { br.ReadInt32(), br.ReadInt32(), br.ReadInt32(), br.ReadInt32(), br.ReadBytes(32), br.ReadInt32(), br.ReadInt32() };

                // Type 16 - Unknown16()
                case 16:
                    return new object[] { br.ReadInt32() };

                // Type 17 - Set_Path(int pathID, int v11) for version 11 else Set_Path(int pathID)
                case 17:
                    if (ver == 11) return new object[] { br.ReadInt32(), br.ReadInt32() };
                    if (ver < 11) return new object[] { br.ReadInt32() };
                    break;

                // Type 18 - Disappear()
                case 18:
                    return new object[0];

                // // Type 19 - N/A
                //case 19:

                // Type 20 - N/A
                //case 20:

                // Type 21 - Respawn()
                case 21:
                    return new object[0];

                // Type 22 - Set_Value(int oldValue, int newValue)
                case 22:
                    return new object[] { br.ReadInt32(), br.ReadInt32() };

                // Type 23 - Add_Value(int value, int toAdd)
                case 23:
                    return new object[] { br.ReadInt32(), br.ReadInt32() };

                // Type 24 - N/A
                //case 24:

                // Type 25 - Set_Mob_Attribute(int mobID, int cycles, int unk1, int name, int unk2)
                case 25:
                    return new object[] { br.ReadInt32(), br.ReadInt32(), br.ReadInt32(), br.ReadInt32(), br.ReadInt32() };

                // Type 26 - Drop_WarSoul(int itemID, int calls, int cycles)
                case 26:
                    return new object[] { br.ReadInt32(), br.ReadInt32(), br.ReadInt32() };
            }

            Cursor = Cursors.Default;
            MessageBox.Show(Resources.UnknownType + type.ToString(CultureInfo.InvariantCulture) + Resources.CRLF);
            return new object[0];
        }

        private string JDConditionName(int operID)
        {
            switch (operID)
            {
                case 0:
                    return Resources.Is_Timer_Ticking;
                case 1:
                    return Resources.Is_HP_Less;
                case 2:
                    return Resources.Is_Combat_Started;
                case 3:
                    return Resources.Randomize;
                case 4:
                    return Resources.Is_Target_Killed;
                case 5:
                    return "!";
                case 6:
                    return "||";
                case 7:
                    return "&&";
                case 8:
                    return Resources.Is_Dead;
                case 9:
                    return Resources.Path_To;
                case 10:
                    return Resources.More_Than;
                case 11:
                    return Resources.Distance_To;
                case 12:
                    return Resources.Unknown12;
                case 13:
                    return Resources.Unknown13;
                case 14:
                    return Resources.Unknown14;
                case 15:
                    return Resources.Unknown15;
                case 16:
                    return ">";
                case 17:
                    return "<";
                case 18:
                    return "=";
                case 19:
                    return Resources.Public_Counter;
                case 20:
                    return Resources.Value;
                case 21:
                    return Resources.Rank;
                case 22:
                    return Resources.Remove_Mob;
                case 23:
                    return Resources.Skill_Cast;
                default:
                    {
                        Cursor = Cursors.Default;
                        MessageBox.Show(Resources.UnkCondType + operID.ToString(CultureInfo.InvariantCulture));
                        return "?";
                    }
            }
        }

        private string JDConditionValue(Condition c)
        {
            switch (c.OperID)
            {
                case 0:    // Is_Timer_Ticking[0]
                case 9:    // Path_To[0]
                case 10:   // More_Than[0]
                case 19:   // Variable[0]
                case 20:   // Variable_Value[0]
                case 21:   // Rank[0]
                case 23:   // Cast_Skill[0]
                    return BitConverter.ToInt32(c.Value, 0).ToString(CultureInfo.InvariantCulture);

                case 1:    // Is_HP_Less[0.00]
                case 3:    // Randomize[0.00]
                case 11:   // Distance_To[0.00]
                    return BitConverter.ToSingle(c.Value, 0).ToString("F2");

                case 2:    // Is_Combat_Started[]
                case 4:    // Is_Target_Killed[]
                case 6:    // ||
                case 7:    // &&
                case 8:    // Is_Dead[]
                case 12:   // Unknown12[]
                case 13:   // Unknown13[]
                case 14:   // Unknown14[]
                case 15:   // Unknown15[]
                case 16:   // >
                case 17:   // <
                case 18:   // =
                case 22:   // Remove_Mob[]
                    return "";

                case 5:    // !
                    return "NOT";
                default:
                    {
                        Cursor = Cursors.Default;
                        var operID = c.OperID;
                        MessageBox.Show(Resources.UnkCondType + operID.ToString(CultureInfo.InvariantCulture));
                        return "?";
                    }
            }
        }

        private string JDConditionExpression(Condition c)
        {
            var text = "";

            if (c.ConditionType == 1)
            {
                text += "(";
                text += JDConditionExpression(c.ConditionLeft);
                text = text + " " + JDConditionName(c.OperID) + " ";
                text += JDConditionExpression(c.ConditionRight);
                text += ")";
            }

            if (c.ConditionType == 2)
            {
                text += JDConditionName(c.OperID);
                text += "(";
                text += JDConditionExpression(c.ConditionRight);
                text += ")";
            }

            if (c.ConditionType > 2)
            {
                text += JDConditionName(c.OperID);
                text += "[";
                if (c.ArgBytes > 0) text += JDConditionValue(c);
                text += "]";
            }

            return text;
        }

        private static string JDProcedureTarget(int target)
        {
            switch (target)
            {
                case 0:
                    return Resources.AGGRO_FIRST;
                case 1:
                    return Resources.AGGRO_SECOND;
                case 2:
                    return Resources.AGGRO_SECOND_RAND;
                case 3:
                    return Resources.MOST_HP;
                case 4:
                    return Resources.MOST_MP;
                case 5:
                    return Resources.LEAST_HP;
                case 6:
                    return Resources.CLASS_COMBO;
                case 7:
                    return Resources.SELF;
                default:
                    return "?";
            }
        }

        // Overloaded JDProcedureTarget
        private static int JDProcedureTarget(string target)
        {
            if (target.ToString(CultureInfo.InvariantCulture) == Resources.AGGRO_FIRST) return 0;
            if (target.ToString(CultureInfo.InvariantCulture) == Resources.AGGRO_SECOND) return 1;
            if (target.ToString(CultureInfo.InvariantCulture) == Resources.AGGRO_SECOND_RAND) return 2;
            if (target.ToString(CultureInfo.InvariantCulture) == Resources.MOST_HP) return 3;
            if (target.ToString(CultureInfo.InvariantCulture) == Resources.MOST_MP) return 4;
            if (target.ToString(CultureInfo.InvariantCulture) == Resources.LEAST_HP) return 5;
            if (target.ToString(CultureInfo.InvariantCulture) == Resources.CLASS_COMBO) return 6;
            return target.ToString(CultureInfo.InvariantCulture) == Resources.SELF ? 7 : 0;
        }

        private static string JDProcedureExpression(Procedure p, int ver)
        {
            var str = "";

            switch (p.Type)
            {
                case 0:
                    str = "Attack(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 1:
                    str = "Cast_Skill(";
                    str = str + ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 2:
                    str = "Broadcast_Message(";
                    str = str + ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str = str + "\"" + Encoding.Unicode.GetString((byte[])p.Parameter[1]).Replace("\0", "") + "\"";
                    str += ")";
                    break;

                case 3:
                    str = "Reset_Aggro()";
                    break;

                case 4:
                    str = "Execute_ActionSet(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 5:
                    str = "Disable_ActionSet(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 6:
                    str = "Enable_ActionSet(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 7:
                    str = "Create_Timer(";
                    str = str + ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str = str + ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[2]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 8:
                    str = "Delete_Timer(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 9:
                    str = "Flee()";
                    break;

                case 10:
                    str = "Be_Taunted()";
                    break;

                case 11:
                    str = "Fade_Target()";
                    break;

                case 12:
                    str = "Fade_Aggro()";
                    break;

                case 13:
                    str = "Break()";
                    break;

                case 14:
                    var paramStr = (int)p.Parameter[1] % 2 < 1 ? "start" : "stop";
                    str = "NPC_Generator(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture) + "[" + paramStr + "]";
                    str += ")";
                    break;

                case 15:
                    str = "Summon_Mob(";
                    str = str + ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str = str + ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str = str + ((int)p.Parameter[2]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str = str + ((int)p.Parameter[3]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str = str + "\"" + Encoding.Unicode.GetString((byte[])p.Parameter[4]).Replace("\0", "") + "\",";
                    str = str + ((int)p.Parameter[5]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[6]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 16:
                    str = "Unknown16(";
                    str = str + ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 17:
                    str = "Set_Path(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture);
                    if (ver == 11) str = str + ", " + ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 18:
                    str = "Disappear()";
                    break;

                case 21:
                    str = "Respawn()";
                    break;

                case 22:
                    str = "Set_Value(";
                    str = str + ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 23:
                    str = "Add_Value(";
                    str = str + ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 24:
                    break;

                case 25:
                    str = "Set_Mob_Attribute(";
                    str = str + ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str = str + ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str = str + ((int)p.Parameter[2]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str = str + ((int)p.Parameter[3]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[4]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 26:
                    str = "Drop_WarSoul(";
                    str = str + ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str = str + ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[2]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;
            }

            str = str + " Target(" + JDProcedureTarget(p.Target);

            if (p.Target == 6)
            {
                var extra = p.TargetParams;
                str = str + ", " + extra;
            }

            return str + ")";
        }

        private object[] JDGetParameters(int type, int ver)
        {
            // Type 0 - Attack(int unk)
            if (type == 0 && textBox_Param1.Text != "")
                return new object[] { Convert.ToInt32(textBox_Param1.Text) };

            // Type 1 - Cast_Skill(int skill_id, int skill_lvl)
            if (type == 1 && textBox_Param1.Text != "" && textBox_Param2.Text != "")
                return new object[]
                {
                    Convert.ToInt32(textBox_Param1.Text),
                    Convert.ToInt32(textBox_Param2.Text)
                };

            // Type 2 - Broadcast_Message(int byteCount, byte[] message)
            if (type == 2 && textBox_Param2.Text != "")
            {
                var unicode = Encoding.Unicode;
                var bytes = unicode.GetBytes(textBox_Param2.Text);
                var byteLen = bytes.Length + 2;
                var message = new byte[byteLen];

                Array.Copy(bytes, message, bytes.Length);
                message[bytes.Length] = 0;
                message[bytes.Length + 1] = 0;
                return new object[] { byteLen, message };
            }

            // Type 3 - Reset_Aggro()
            if (type == 3) return new object[0];

            // Type 4 - Execute_ActionSet(int actionset_id)
            if (type == 4 && textBox_Param1.Text != "")
                return new object[] { Convert.ToInt32(textBox_Param1.Text) };

            // Type 5 - Disable_ActionSet(int actionset_id)
            if (type == 5 && textBox_Param1.Text != "")
                return new object[] { Convert.ToInt32(textBox_Param1.Text) };

            // Type 6 - Enable_ActionSet(int actionset_id)
            if (type == 6 && textBox_Param1.Text != "")
                return new object[] { Convert.ToInt32(textBox_Param1.Text) };

            // Type 7 - Create_Timer(int timerID, int delay, int cycles)
            if (type == 7 && textBox_Param1.Text != "" && textBox_Param2.Text != "" && textBox_Param3.Text != "")
                return new object[]
                {
                    Convert.ToInt32(textBox_Param1.Text),
                    Convert.ToInt32(textBox_Param2.Text),
                    Convert.ToInt32(textBox_Param3.Text)
                };

            // Type 8 - Delete_Timer(int timerID)
            if (type == 8 && textBox_Param1.Text != "")
                return new object[] { Convert.ToInt32(textBox_Param1.Text) };

            // Type 9 - Flee()
            if (type == 9) return new object[0];

            // Type 10 - Be_Taunted()
            if (type == 10) return new object[0];

            // Type 11 - Fade_Target()
            if (type == 11) return new object[0];

            // Type 12 - Fade_Aggro()
            if (type == 12) return new object[0];

            // Type 13 - Break()
            if (type == 13) return new object[0];

            // Type 14 - NPC_Generator(int triggerID, int ctrlParam)
            if (type == 14 && textBox_Param1.Text != "" && textBox_Param2.Text != "")
                return
                    new object[]
                    {
                        Convert.ToInt32(textBox_Param1.Text),
                        Convert.ToInt32(textBox_Param2.Text)
                    };

            // Type 15 - Summon_Mob(int elementsID, int timeInterval, int calls, int Survival, string mobName, int refreshRange, int unknown)
            if (type == 15 && textBox_Param1.Text != "" && textBox_Param2.Text != "" &&
                textBox_Param3.Text != "" && textBox_Param4.Text != "" && textBox_Param5.Text != "" &&
                textBox_Param6.Text != "" && textBox_Param7.Text != "")
            {
                var mobName = new byte[32];
                var msgSize = Encoding.Unicode.GetBytes(textBox_Param5.Text);

                if (msgSize.Length < 32)
                {
                    Array.Copy(msgSize, mobName, msgSize.Length);
                    for (var i = msgSize.Length; i < 32; i++) mobName[i] = 0;
                }
                else Array.Copy(msgSize, mobName, 32);

                return new object[]
                {
                    Convert.ToInt32(textBox_Param1.Text),
                    Convert.ToInt32(textBox_Param2.Text),
                    Convert.ToInt32(textBox_Param3.Text),
                    Convert.ToInt32(textBox_Param4.Text),
                    mobName,
                    Convert.ToInt32(textBox_Param6.Text),
                    Convert.ToInt32(textBox_Param7.Text)
                };
            }

            // Type 16 - Unknown16(int unkInt string unkStr)
            if (type == 16 && textBox_Param1.Text != "")
                return new object[] { Convert.ToInt32(textBox_Param1.Text) };

            // Type 17 - Set_Path(int pathID)
            //      if version = 11 then Set_Path(int pathID, int v11Path)
            if (type == 17 && textBox_Param1.Text != "")
            {
                return ver == 11 ? new object[] {Convert.ToInt32(textBox_Param1.Text),
                    Convert.ToInt32(textBox_Param2.Text)} : new object[] { Convert.ToInt32(textBox_Param1.Text) };
            }

            // Type 18 - Disappear()
            if (type == 18) return new object[0];

            // Type 19 - N/A

            // Type 20 - N/A

            // Type 21 - Respawn()
            if (type == 21) return new object[0];

            // Type 22 - Set_Value(int oldValue, int newValue)
            if (type == 22 && textBox_Param1.Text != "" && textBox_Param2.Text != "")
                return new object[]
                {
                    Convert.ToInt32(textBox_Param1.Text),
                    Convert.ToInt32(textBox_Param2.Text)
                };

            // Type 23 - Add_Value(int value, int toAdd)
            if (type == 23 && textBox_Param1.Text != "" && textBox_Param2.Text != "")
                return new object[]
                {
                    Convert.ToInt32(textBox_Param1.Text),
                    Convert.ToInt32(textBox_Param2.Text)
                };

            // Type 24 - N/A

            // Type 25 - Set_Mob_Attribute(int mobID, int cycles, int unk1, int name, int unk2)
            if (type == 25 && textBox_Param1.Text != "" && textBox_Param2.Text != "" &&
                textBox_Param3.Text != "" && textBox_Param4.Text != "" && textBox_Param5.Text != "")
                return new object[]
                {
                    Convert.ToInt32(textBox_Param1.Text),
                    Convert.ToInt32(textBox_Param2.Text),
                    Convert.ToInt32(textBox_Param3.Text),
                    Convert.ToInt32(textBox_Param4.Text),
                    Convert.ToInt32(textBox_Param5.Text)
                };

            // Type 26 - Drop_WarSoul(int itemID, int calls, int cycles)
            if (type == 26 && textBox_Param1.Text != "" && textBox_Param2.Text != "" && textBox_Param3.Text != "")
                return new object[]
                {
                    Convert.ToInt32(textBox_Param1.Text),
                    Convert.ToInt32(textBox_Param2.Text),
                    Convert.ToInt32(textBox_Param3.Text)
                };

            // Type Error
            Cursor = Cursors.Default;
            MessageBox.Show(Resources.ErrParamsWrong);
            return null;
        }

        private static Condition JDGetCondition(string s)
        {
            var pos = 1;
            var len = 0;
            var str = s.Substring(1);

            if (s[0] == '(')
            {
                var ndx = 1;

                while (ndx <= str.Length && pos >= 0)
                {
                    if (s[ndx] == ')')
                    {
                        pos--;
                        len = ndx;
                    }

                    if (s[ndx] == '(') pos++;
                    ndx++;
                }

                if (len == 0 || pos != 0) return null;

                if (len == str.Length)
                {
                    s = str.Substring(0, len - 1);
                    return JDGetCondition(s);
                }
            }

            var length = 0;
            var stack1 = new Stack();
            var stack2 = new Stack();
            var text = s.Substring(length, 1);

            while (text != "" || stack1.Count != 0)
            {
                if (Common.IsNumber(text))
                {
                    text = Common.GetNumber(s.Substring(length));
                    stack2.Push(text);
                    length += text.Length;
                }
                else
                {
                    string s2;
                    if (text == "(")
                    {
                        if (stack1.Count != 0)
                        {
                            length--;
                            s2 = s.Substring(0, length);
                            str = s.Substring(length + 1);

                            var condition = new Condition { OperID = Common.JDIDOper(stack1.Pop().ToString()) };
                            condition.ConditionType = Common.GetOperPrime(condition.OperID);
                            condition.ArgBytes = Common.GetOperArgBytes(condition.OperID);
                            condition.Value = new byte[condition.ArgBytes];

                            if (condition.ConditionType == 1)
                            {
                                condition.ConditionLeft = JDGetCondition(s2);
                                condition.SubNodeL = Common.GetSubNodeL(condition.OperID);
                                condition.ConditionRight = JDGetCondition(str);
                                condition.SubNodeR = Common.GetSubNodeR(condition.OperID);
                            }

                            if (condition.ConditionType == 2)
                            {
                                condition.ConditionRight = JDGetCondition(str);
                                condition.SubNodeL = Common.GetSubNodeL(condition.OperID);
                            }

                            return condition;
                        }
                        length = len + 1;
                    }
                    else
                    {
                        if (stack1.Count != 0 && (text == "" || Common.GetOperPrime(Common.JDIDOper(stack1.Peek().ToString())) <=
                            Common.GetOperPrime(Common.JDIDOper(text))))
                        {
                            length--;
                            s2 = s.Substring(0, length);
                            str = s.Substring(length + 1);

                            var condition = new Condition { OperID = Common.JDIDOper(stack1.Pop().ToString()) };
                            condition.ConditionType = Common.GetOperPrime(condition.OperID);
                            condition.ArgBytes = Common.GetOperArgBytes(condition.OperID);

                            var value = new byte[condition.ArgBytes];

                            switch (condition.OperID)
                            {
                                case 0:
                                case 9:
                                case 10:
                                case 19:
                                case 20:
                                case 21:
                                case 23:
                                    value = BitConverter.GetBytes(Convert.ToInt32(stack2.Pop().ToString()));
                                    break;

                                case 1:
                                case 3:
                                case 11:
                                    value = BitConverter.GetBytes(Convert.ToSingle(stack2.Pop().ToString()));
                                    break;
                            }

                            condition.Value = value;

                            if (condition.ConditionType == 1)
                            {
                                condition.ConditionLeft = JDGetCondition(s2);
                                condition.SubNodeL = Common.GetSubNodeL(condition.OperID);
                                condition.ConditionRight = JDGetCondition(str);
                                condition.SubNodeR = Common.GetSubNodeR(condition.OperID);
                            }

                            if (condition.ConditionType == 2)
                            {
                                condition.ConditionRight = JDGetCondition(str);
                                condition.SubNodeL = Common.GetSubNodeL(condition.OperID);
                            }

                            return condition;
                        }

                        stack1.Push(text);
                        length++;
                    }
                }

                text = length < s.Length ? s.Substring(length, 1) : "";
            }

            return null;
        }

        private Condition JDFixCondition(Condition c)
        {
            if (c.OperID == 22) return AI.ActionController[441].ActionSet[0].Condition;
            if (c.OperID > 23) return null;

            if (c.ConditionType == 1)
            {
                c.ConditionLeft = JDFixCondition(c.ConditionLeft);
                c.ConditionRight = JDFixCondition(c.ConditionRight);

                if (c.ConditionLeft != null && c.ConditionRight != null) return c;
                if (c.ConditionLeft == null && c.ConditionRight != null) return c.ConditionRight;
                if (c.ConditionLeft != null && c.ConditionRight == null) return c.ConditionLeft;
                if (c.ConditionLeft == null && c.ConditionRight == null) return null;
            }

            if (c.ConditionType == 2)
            {
                c.ConditionRight = JDFixCondition(c.ConditionRight);
                return c.ConditionRight != null ? c : null;
            }

            return c;
        }

        private void JDProcedureList()
        {
            label_Param2.BackColor = Color.Transparent;

            switch (comboBox_Proc.SelectedIndex)
            {
                // Attack(int unk)
                case 0:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Attack;
                    label_Param1.Text = Resources.AttackParam;
                    break;

                // Cast_Skill(int skill_id, int skill_lvl)
                case 1:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Cast_Skill;
                    label_Param1.Text = Resources.SkillID;
                    label_Param2.Text = Resources.SkillLevel;
                    break;

                // Broadcast_Message(int byteCount, byte[] message)
                case 2:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Broadcast_Message;
                    label_Param1.Text = Resources.ByteCount;
                    label_Param2.Text = Resources.Message;
                    label_Param2.BackColor = Color.Gold;
                    break;

                // Reset_Aggro()
                case 3:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Reset_Aggro;
                    break;

                // Execute_ActionSet(int actionset_id)
                case 4:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Execute_ActionSet;
                    label_Param1.Text = Resources.ActionSetID;
                    break;

                // Disable_ActionSet(int actionset_id)
                case 5:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Disable_ActionSet;
                    label_Param1.Text = Resources.ActionSetID;
                    break;

                // Enable_ActionSet(int actionset_id)
                case 6:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Enable_ActionSet;
                    label_Param1.Text = Resources.ActionSetID;
                    break;

                // Create_Timer(int timerID, int delay, int cycles)
                case 7:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Create_Timer;
                    label_Param1.Text = Resources.TimerID;
                    label_Param2.Text = Resources.Delay;
                    label_Param3.Text = Resources.Cycles;
                    break;

                // Delete_Timer(int timerID)
                case 8:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Delete_Timer;
                    label_Param1.Text = Resources.TimerID;
                    break;

                // Flee()
                case 9:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Flee;
                    break;

                // Be_Taunted()
                case 10:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Be_Taunted;
                    break;

                // Fade_Target()
                case 11:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Fade_Target;
                    break;

                // Fade_Aggro()
                case 12:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Fade_Aggro;
                    break;

                // Break()
                case 13:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Break;
                    break;

                // NPC_Generator(int triggerID, int ctrlParam)
                case 14:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.NPC_Generator;
                    label_Param1.Text = Resources.TriggerID;
                    label_Param2.Text = Resources.Control;
                    break;

                // Summon_Mob(int elementsID, int timeInterval, int calls, int Survival, string mobName, int refreshRange, int unknown)
                case 15:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Summon_Mob;
                    label_Param1.Text = Resources.ElementsID;
                    label_Param2.Text = Resources.TimeInterval;
                    label_Param3.Text = Resources.Calls;
                    label_Param4.Text = Resources.Survival;
                    label_Param5.Text = Resources.MobName;
                    label_Param6.Text = Resources.RefreshRange;
                    label_Param7.Text = Resources.Unknown;
                    break;

                // Unknown16(int unknown)
                case 16:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Unknown16;
                    label_Param1.Text = Resources.Unknown;
                    break;

                // Set_Path(int pathID)
                // if version == 11 then Set_Path(int pathID, int v11Path)
                case 17:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Set_Path;
                    label_Param1.Text = Resources.PathID;
                    label_Param2.Text = Resources.v11Path;
                    break;

                // Disappear()
                case 18:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Disappear;
                    break;

                // N/A
                case 19:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.NA;
                    break;

                // N/A
                case 20:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.NA;
                    break;

                // Respawn()
                case 21:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Respawn;
                    break;

                // Set_Value(int Value, int Amount)
                case 22:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Set_Value;
                    label_Param1.Text = Resources.Value;
                    label_Param2.Text = Resources.EQUAL;
                    break;

                // Add_Value(int Value, int Amount)
                case 23:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Add_Value;
                    label_Param1.Text = Resources.Value;
                    label_Param2.Text = Resources.PLUS;
                    break;

                // N/A
                case 24:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.NA;
                    break;

                // Set_Mob_Attribute(int mobID, int cycles, int unk1, int name, int unk2)
                case 25:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Set_Mob_Attribute;
                    label_Param1.Text = Resources.MobID;
                    label_Param2.Text = Resources.Cycles;
                    label_Param3.Text = Resources.Unknown;
                    label_Param4.Text = Resources.MobName;
                    label_Param5.Text = Resources.Unknown;
                    break;

                // Drop_WarSoul(int itemID, int calls, int cycles)
                case 26:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Drop_WarSoul;
                    label_Param1.Text = Resources.ItemID;
                    label_Param2.Text = Resources.Calls;
                    label_Param3.Text = Resources.Cycles;
                    break;
            }
        }

        private static void JDSaveCondition(Condition c, BinaryWriter bw)
        {
            bw.Write(c.OperID);
            bw.Write(c.ArgBytes);
            bw.Write(c.Value);
            bw.Write(c.ConditionType);

            if (c.ConditionType == 1)
            {
                JDSaveCondition(c.ConditionLeft, bw);
                bw.Write(c.SubNodeL);

                if (c.SubNodeL == 2)
                {
                    JDSaveCondition(c.ConditionRight, bw);
                    bw.Write(c.SubNodeR);
                }
            }

            if (c.ConditionType != 2) return;

            JDSaveCondition(c.ConditionRight, bw);
            bw.Write(c.SubNodeL);
        }

        private static void JDWriteParameters(int type, IList<object> parameters, BinaryWriter bw, int ver)
        {
            switch (type)
            {
                // Type 0 - Attack(int unk)
                case 0:
                    bw.Write((int)parameters[0]);
                    break;

                // Type 1 - Cast_Skill(int skill_id, int skill_lvl)
                case 1:
                    bw.Write((int)parameters[0]);
                    bw.Write((int)parameters[1]);
                    break;

                // Type 2 - Broadcast_Message(int byteCount, byte[] message)
                case 2:
                    var value = (int)parameters[0];
                    bw.Write(value);
                    bw.Write((byte[])parameters[1]);
                    break;

                // Type 3 - Reset_Aggro()
                // no parameters...
                case 3:
                    break;

                // Type 4 - Execute_ActionSet(int actionset_id)
                case 4:
                    bw.Write((int)parameters[0]);
                    break;

                // Type 5 - Disable_ActionSet(int actionset_id)
                case 5:
                    bw.Write((int)parameters[0]);
                    break;

                // Type 6 - Enable_ActionSet(int actionset_id)
                case 6:
                    bw.Write((int)parameters[0]);
                    break;

                // Type 7 - Create_Timer(int timerID, int delay, int cycles)
                case 7:
                    bw.Write((int)parameters[0]);
                    bw.Write((int)parameters[1]);
                    bw.Write((int)parameters[2]);
                    break;

                // Type 8 - Delete_Timer(int timerID)
                case 8:
                    bw.Write((int)parameters[0]);
                    break;

                // Type 9 - Flee()
                // no parameters...
                case 9:

                // Type 10 - Be_Taunted()
                // no parameters...
                case 10:

                // Type 11 - Fade_Target()
                // no parameters...
                case 11:

                // Type 12 - Fade_Aggro()
                // no parameters...
                case 12:

                // Tpye 13 - Break()
                // no parameters...
                case 13:
                    break;

                // Type 14 - NPC_Generator(int triggerID, int ctrlParam)
                case 14:
                    bw.Write((int)parameters[0]);
                    bw.Write((int)parameters[1]);
                    break;

                // Type 15 - Summon_Mob(int elementsID, int timeInterval, int calls, int Survival, string mobName, int refreshRange, int unknown)
                case 15:
                    bw.Write((int)parameters[0]);
                    bw.Write((int)parameters[1]);
                    bw.Write((int)parameters[2]);
                    bw.Write((int)parameters[3]);
                    bw.Write((byte[])parameters[4]);
                    bw.Write((int)parameters[5]);
                    bw.Write((int)parameters[6]);
                    break;

                // Type 16 - Unknown16(int unk)
                case 16:
                    bw.Write((int)parameters[0]);
                    break;

                // Type 17 - Set_Path(int pathID)
                // if version = 11 then Set_Path(int pathID, int v11Path)
                case 17:
                    bw.Write((int)parameters[0]);
                    if (ver == 11) bw.Write((int)parameters[1]);
                    break;

                // Type 18 - Disappear()
                case 18:

                // Type 19 - N/A
                case 19:

                // Type 20 - N/A
                case 20:

                // Type 21 - Respawn()
                case 21:
                    break;

                // Type 22- Set_Value(int oldValue, int newValue)
                case 22:
                    bw.Write((int)parameters[0]);
                    bw.Write((int)parameters[1]);
                    break;

                // Type 23- Add_Value(int value, int toAdd)
                case 23:
                    bw.Write((int)parameters[0]);
                    bw.Write((int)parameters[1]);
                    break;

                // Type 24-  N/A
                case 24:
                    break;

                // Type 25 - Set_Mob_Attribute(int mobID, int cycles, int unk1, int name, int unk2)
                case 25:
                    bw.Write((int)parameters[0]);
                    bw.Write((int)parameters[1]);
                    bw.Write((int)parameters[2]);
                    bw.Write((int)parameters[3]);
                    bw.Write((int)parameters[4]);
                    break;

                // Type 26 - Drop_WarSoul(int itemID, int calls, int cycles)
                case 26:
                    bw.Write((int)parameters[0]);
                    bw.Write((int)parameters[1]);
                    bw.Write((int)parameters[2]);
                    break;
            }
        }

        //*************************************************************
        //               Perfect World Specific
        //*************************************************************

        private static object[] PWReadParameters(int type, BinaryReader br)
        {
            switch (type)
            {
                // Type 0 - Attack(int unk)
                case 0:
                    return new object[] { br.ReadInt32() };

                // Type 1 - Cast_Skill(int skill_id, int skill_lvl)
                case 1:
                    return new object[] { br.ReadInt32(), br.ReadInt32() };

                // Type 2 - Broadcast_Message(int byteCount, byte[] message)
                case 2:
                    var byteCount = br.ReadInt32();
                    return new object[] { byteCount, br.ReadBytes(byteCount) };

                // Type 3 - Reset_Aggro()
                case 3:
                    return new object[0];

                // Type 4 - Exec_ActionSet(int actionset_id)
                case 4:
                    return new object[] { br.ReadInt32() };

                // Type 5 - Disable_ActionSet(int actionset_id)
                case 5:
                    return new object[] { br.ReadInt32() };

                // Type 6 - Enable_ActionSet(int actionset_id)
                case 6:
                    return new object[] { br.ReadInt32() };

                // Type 7 - Create_Timer(int timerID, int delay, int cycles)
                case 7:
                    return new object[] { br.ReadInt32(), br.ReadInt32(), br.ReadInt32() };

                // Type 8 - Delete_Timer(int timerID)
                case 8:
                    return new object[] { br.ReadInt32() };

                // Type 9 - Flee()
                case 9:
                    return new object[0];

                // Type 10 - Be_Taunted()
                case 10:

                // Type 11 - Fade_Target()
                case 11:

                // Type 12 - Fade_Aggro()
                case 12:

                // Type 13 - Break()
                case 13:
                    return new object[0];

                // Type 14 - NPC_Generator(int triggerID, int ctrlParam)
                case 14:
                    return new object[] { br.ReadInt32(), br.ReadInt32() };

                // Type 15 - Initialize_Public_Counter(int x, int y, int z)
                case 15:
                    return new object[] { br.ReadInt32(), br.ReadInt32(), br.ReadInt32() };

                // Type 16 - Increment_Public_Counter(int x, int y)
                case 16:
                    return new object[] { br.ReadInt32(), br.ReadInt32() };

                // Type 17 - Player_Aimed_NPC_Spawn(int elementsID, int timeInterval, int calls, int Survival, string mobName, int refreshRange, int unknown)
                case 17:
                    return new object[] { br.ReadInt32(), br.ReadInt32(), br.ReadInt32(), br.ReadInt32(), br.ReadInt32(), br.ReadInt32() };

                // Type 18 - Change_Path(int w, int x, int y, int z)
                case 18:
                    return new object[] { br.ReadInt32(), br.ReadInt32(), br.ReadInt32(), br.ReadInt32() };

                // Type 19 - Play_Action(sting w, int x, int y, int z)
                case 19:
                    return new object[] { br.ReadBytes(128), br.ReadInt32(), br.ReadInt32(), br.ReadInt32() };
                case 62:
                    return new object[] { br.ReadInt32(), br.ReadInt32(), br.ReadInt32(), br.ReadInt32() };

                // default - unknown Type
                default:
                    if (type > 19) MessageBox.Show(Resources.UnknownType + type);
                    return new object[0];
            }
        }

        private static object[] PWReadTargetParameters(int type, BinaryReader br)
        {
            switch (type)
            {
                case 6:
                    return new object[] { br.ReadInt32() };
                default:
                    return new object[0];
            }
        }

        private static string PWConditionName(int operID)
        {
            switch (operID)
            {
                case 0:
                    return Resources.Is_Timer_Ticking;
                case 1:
                    return Resources.Is_HP_Less;
                case 2:
                    return Resources.Is_Combat_Started;
                case 3:
                    return Resources.Randomize;
                case 4:
                    return Resources.Is_Target_Killed;
                case 5:
                    return "!";
                case 6:
                    return "||";
                case 7:
                    return "&&";
                case 8:
                    return Resources.Is_Dead;
                case 9:
                    return "+";
                case 10:
                    return "-";
                case 11:
                    return "==";
                case 12:
                    return ">";
                case 13:
                    return ">=";
                case 14:
                    return "<";
                case 15:
                    return ">";
                case 16:
                    return Resources.Public_Counter;
                case 17:
                    return Resources.Value;
                case 18:
                    return "Is_Event?";
                default:
                    return "?";
            }
        }

        private static string PWConditionValue(Condition c)
        {
            switch (c.OperID)
            {
                case 0:    // Is_Timer_Ticking[0]
                case 16:   // Public_Counter[0]
                case 17:   // Value[0]
                    return BitConverter.ToInt32(c.Value, 0).ToString(CultureInfo.InvariantCulture);

                case 1:    // Is_HP_Less[0.00]
                case 3:    // Randomize[0.00]
                    return BitConverter.ToSingle(c.Value, 0).ToString("F2");

                case 2:    // Is_Combat_Started[]
                case 4:    // Is_Target_Killed[]
                case 6:    // ||
                case 7:    // &&
                case 8:    // Is_Dead[]
                case 9:    // +
                case 10:   // -
                case 11:   // ==
                case 12:   // >
                case 13:   // >=
                case 14:   // (space)
                case 15:   // >
                case 18:   // Is_Event[]?
                    return "";

                case 5:    // !
                    return "NOT";

                default:
                    return "?";
            }
        }

        private static string PWConditionExpression(Condition c)
        {
            var text = "";

            if (c.ConditionType == 1)
            {
                text += "(";
                text += PWConditionExpression(c.ConditionLeft);
                text += " " + PWConditionName(c.OperID) + " ";
                text += PWConditionExpression(c.ConditionRight);
                text += ")";
            }

            if (c.ConditionType == 2)
            {
                text += PWConditionName(c.OperID);
                text += "(";
                text += PWConditionExpression(c.ConditionRight);
                text += ")";
            }

            if (c.ConditionType > 2)
            {
                text += PWConditionName(c.OperID);
                text += "[";
                if (c.ArgBytes > 0) text += PWConditionValue(c);
                text += "]";
            }

            return text;
        }

        private static string PWProcedureTarget(int target, IList<object> targetParameters)
        {
            switch (target)
            {
                case 0:
                    return "AGGRO_FIRST";
                case 1:
                    return "AGGRO_SECOND";
                case 2:
                    return "AGGRO_SECOND_RAND";
                case 3:
                    return "MOST_HP";
                case 4:
                    return "MOST_MP";
                case 5:
                    return "LEAST_HP";
                case 6:
                    return "CLASS_COMBO," + targetParameters[0];
                case 7:
                    return "SELF";
                default:
                    return "?";
            }
        }

        // Overloaded PWProcedureTarget
        private static int PWProcedureTarget(string target)
        {
            if (target.ToString(CultureInfo.InvariantCulture) == "AGGRO_FIRST") return 0;
            if (target.ToString(CultureInfo.InvariantCulture) == "AGGRO_SECOND") return 1;
            if (target.ToString(CultureInfo.InvariantCulture) == "AGGRO_SECOND_RAND") return 2;
            if (target.ToString(CultureInfo.InvariantCulture) == "MOST_HP") return 3;
            if (target.ToString(CultureInfo.InvariantCulture) == "MOST_MP") return 4;
            if (target.ToString(CultureInfo.InvariantCulture) == "LEAST_HP") return 5;
            if (target.ToString(CultureInfo.InvariantCulture) == "CLASS_COMBO") return 6; // will have to fix this...
            if (target.ToString(CultureInfo.InvariantCulture) == "SELF") return 7;
            return 0; // defaults to AGGRO_MOST as it is the most common
        }

        private static string PWProcedureExpression(Procedure p)
        {
            var str = "";

            switch (p.Type)
            {
                case 0:
                    str = "Attack(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 1:
                    str = "Cast_Skill(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 2:
                    str = "Broadcast_Message(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += "\"" + Encoding.Unicode.GetString((byte[])p.Parameter[1]).Replace("\0", "") + "\"";
                    str += ")";
                    break;

                case 3:
                    str = "Reset_Aggro()";
                    break;

                case 4:
                    str = "Execute_ActionSet(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 5:
                    str = "Disable_ActionSet(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 6:
                    str = "Enable_ActionSet(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 7:
                    str = "Create_Timer(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[2]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 8:
                    str = "Remove_Timer(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 9:
                    str = "Flee()";
                    break;

                case 10:
                    str = "Be_Taunted()";
                    break;

                case 11:
                    str = "Fade_Target()";
                    break;

                case 12:
                    str = "Fade_Aggro()";
                    break;

                case 13:
                    str = "Break()";
                    break;

                case 14:
                    var paramStr = (int)p.Parameter[1] % 2 < 1 ? "start" : "stop";
                    str = "NPC_Generator(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture) + "[" + paramStr + "]";
                    str += ")";
                    break;

                case 15:
                    str = "Initialize_Public_Counter(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[2]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 16:
                    str = "Increment_Public_Counter(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 17:
                    str = "Player_Aimed_NPC_Spawn(";
                    str = str + ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str = str + ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str = str + ((int)p.Parameter[2]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str = str + ((int)p.Parameter[3]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str = str + ((int)p.Parameter[4]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[5]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 18:
                    str = "Change_Path(";
                    str += ((int)p.Parameter[0]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[2]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[3]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;

                case 19:
                    str = "Play_Action(";
                    str += "\"" + Encoding.GetEncoding("GBK").GetString((byte[])p.Parameter[0]).Replace("\0", "") + "\", ";
                    str += ((int)p.Parameter[1]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[2]).ToString(CultureInfo.InvariantCulture) + ", ";
                    str += ((int)p.Parameter[3]).ToString(CultureInfo.InvariantCulture);
                    str += ")";
                    break;
            }

            return str + (" " + PWProcedureTarget(p.Target, p.TargetParams));
        }

        private object[] PWGetParameters(int type)
        {
            // Type 0 - Attack(int unk)
            if (type == 0 && textBox_Param1.Text != "")
                return new object[] { Convert.ToInt32(textBox_Param1.Text) };

            // Type 1 - Cast_Skill(int skill_id, int skill_lvl)
            if (type == 1 && textBox_Param1.Text != "" && textBox_Param2.Text != "")
                return new object[]
                {
                    Convert.ToInt32(textBox_Param1.Text),
                    Convert.ToInt32(textBox_Param2.Text)
                };

            // Type 2 - Broadcast_Message(int byteCount, byte[] message)
            if (type == 2 && textBox_Param2.Text != "")
            {
                var unicode = Encoding.Unicode;
                var bytes = unicode.GetBytes(textBox_Param2.Text);
                var param1 = bytes.Length + 2;
                var message = new byte[param1];
                Array.Copy(bytes, message, bytes.Length);
                message[bytes.Length] = 0;
                message[bytes.Length + 1] = 0;
                return new object[] { param1, message };
            }

            // Type 3 - Reset_Aggro()
            if (type == 3) return new object[0];

            // Type 4 - Execute_ActionSet(int actionset_id)
            if (type == 4 && textBox_Param1.Text != "")
                return new object[] { Convert.ToInt32(textBox_Param1.Text) };

            // Type 5 - Disable_ActionSet(int actionset_id)
            if (type == 5 && textBox_Param1.Text != "")
                return new object[] { Convert.ToInt32(textBox_Param1.Text) };

            // Type 6 - Enable_ActionSet(int actionset_id)
            if (type == 6 && textBox_Param1.Text != "")
                return new object[] { Convert.ToInt32(textBox_Param1.Text) };

            // Type 7 - Create_Timer(int timerID, int delay, int cycles)
            if (type == 7 && textBox_Param1.Text != "" && textBox_Param2.Text != "" && textBox_Param3.Text != "")
                return new object[]
                {
                    Convert.ToInt32(textBox_Param1.Text),
                    Convert.ToInt32(textBox_Param2.Text),
                    Convert.ToInt32(textBox_Param3.Text)
                };

            // Type 8 - Delete_Timer(int timerID)
            if (type == 8 && textBox_Param1.Text != "")
                return new object[] { Convert.ToInt32(textBox_Param1.Text) };

            // Type 9 - Flee()
            if (type == 9) return new object[0];

            // Type 10 - Be_Taunted()
            if (type == 10) return new object[0];

            // Type 11 - Fade_Target()
            if (type == 11) return new object[0];

            // Type 12 - Fade_Aggro()
            if (type == 12) return new object[0];

            // Type 13 - Break()
            if (type == 13) return new object[0];

            // Type 14 - NPC_Generator(int triggerID, int ctrlParam)
            if (type == 14 && textBox_Param1.Text != "" && textBox_Param2.Text != "")
                return new object[] { Convert.ToInt32(textBox_Param1.Text),
                    Convert.ToInt32(textBox_Param2.Text) };

            // Type 15 - Initialize_Public_Counter(int x, int y, int z)
            if (type == 15 && textBox_Param1.Text != "" && textBox_Param2.Text != "" && textBox_Param3.Text != "")
                return new object[]
                {
                    Convert.ToInt32(textBox_Param1.Text),
                    Convert.ToInt32(textBox_Param2.Text),
                    Convert.ToInt32(textBox_Param3.Text)
                };

            // Type 16 - Increment_Public_Counter(int x, int y)
            if (type == 16 && textBox_Param1.Text != "" && textBox_Param2.Text != "")
                return new object[]
                { 
                    Convert.ToInt32(textBox_Param1.Text),
                    Convert.ToInt32(textBox_Param2.Text)
                };

            // Type 17 - Player_Aimed_NPC_Spawn(int elementsID, int timeInterval, int calls, int Survival, string mobName, int refreshRange, int unknown)
            if (type == 17 && textBox_Param1.Text != "" && textBox_Param2.Text != "" &&
                textBox_Param3.Text != "" && textBox_Param4.Text != "" && textBox_Param5.Text != "" &&
                textBox_Param6.Text != "" && textBox_Param7.Text != "")
            {
                var mobName = new byte[32];
                var msgSize = Encoding.Unicode.GetBytes(textBox_Param5.Text);

                if (msgSize.Length < 32)
                {
                    Array.Copy(msgSize, mobName, msgSize.Length);
                    for (var i = msgSize.Length; i < 32; i++) mobName[i] = 0;
                }
                else Array.Copy(msgSize, mobName, 32);

                return new object[]
                {
                    Convert.ToInt32(textBox_Param1.Text),
                    Convert.ToInt32(textBox_Param2.Text),
                    Convert.ToInt32(textBox_Param3.Text),
                    Convert.ToInt32(textBox_Param4.Text),
                    mobName,
                    Convert.ToInt32(textBox_Param6.Text),
                    Convert.ToInt32(textBox_Param7.Text)
                };
            }

            // Type 18 - Change_Path(int w, int x, int y, int z)
            if (type == 18 && textBox_Param1.Text != "" && textBox_Param2.Text != "" && textBox_Param3.Text != "")
                return new object[]
                {
                    Convert.ToInt32(textBox_Param1.Text),
                    Convert.ToInt32(textBox_Param2.Text),
                    Convert.ToInt32(textBox_Param3.Text)
                };

            // Type 19 - Play_Action(sting w, int x, int y, int z)
            if (type == 19 && textBox_Param1.Text != "" && textBox_Param2.Text != "" && textBox_Param3.Text != "" &&
                textBox_Param4.Text != "")
                return new object[]
                {
                    Convert.ToInt32(textBox_Param1.Text),
                    Convert.ToInt32(textBox_Param2.Text),
                    Convert.ToInt32(textBox_Param3.Text),
                    Convert.ToInt32(textBox_Param4.Text)
                };

            // Type Error
            Cursor = Cursors.Default;
            MessageBox.Show(Resources.ErrParamsWrong);
            return null;
        }

        private static Condition PWGetCondition(string s)
        {
            var pos = 1;
            var len = 0;
            var str = s.Substring(1);

            if (s[0] == '(')
            {
                var ndx = 1;

                while (ndx <= str.Length && pos >= 0)
                {
                    if (s[ndx] == ')')
                    {
                        pos--;
                        len = ndx;
                    }

                    if (s[ndx] == '(') pos++;
                    ndx++;
                }

                if (len == 0 || pos != 0) return null;

                if (len == str.Length)
                {
                    s = str.Substring(0, len - 1);
                    return PWGetCondition(s);
                }
            }

            var length = 0;
            var stack1 = new Stack();
            var stack2 = new Stack();
            var text = s.Substring(length, 1);

            while (text != "" || stack1.Count != 0)
            {
                if (Common.IsNumber(text))
                {
                    text = Common.GetNumber(s.Substring(length));
                    stack2.Push(text);
                    length += text.Length;
                }
                else
                {
                    string s2;
                    if (text == "(")
                    {
                        if (stack1.Count != 0)
                        {
                            length--;
                            s2 = s.Substring(0, length);
                            str = s.Substring(length + 1);

                            var condition = new Condition { OperID = Common.PWIDOper(stack1.Pop().ToString()) };
                            condition.ConditionType = Common.GetOperPrime(condition.OperID);
                            condition.ArgBytes = Common.GetOperArgBytes(condition.OperID);
                            condition.Value = new byte[condition.ArgBytes];

                            if (condition.ConditionType == 1)
                            {
                                condition.ConditionLeft = PWGetCondition(s2);
                                condition.SubNodeL = Common.GetSubNodeL(condition.OperID);
                                condition.ConditionRight = PWGetCondition(str);
                                condition.SubNodeR = Common.GetSubNodeR(condition.OperID);
                            }

                            if (condition.ConditionType == 2)
                            {
                                condition.ConditionRight = PWGetCondition(str);
                                condition.SubNodeL = Common.GetSubNodeL(condition.OperID);
                            }

                            return condition;
                        }

                        length = len + 1;
                    }
                    else
                    {
                        if (stack1.Count != 0 && (text == "" || Common.GetOperPrime(Common.PWIDOper(stack1.Peek().ToString())) <=
                            Common.GetOperPrime(Common.PWIDOper(text))))
                        {
                            length--;
                            s2 = s.Substring(0, length);
                            str = s.Substring(length + 1);

                            var condition = new Condition { OperID = Common.PWIDOper(stack1.Pop().ToString()) };
                            condition.ConditionType = Common.GetOperPrime(condition.OperID);
                            condition.ArgBytes = Common.GetOperArgBytes(condition.OperID);

                            var value = new byte[condition.ArgBytes];

                            switch (condition.OperID)
                            {
                                case 0:
                                case 16:
                                case 17:
                                    value = BitConverter.GetBytes(Convert.ToInt32(stack2.Pop().ToString()));
                                    break;

                                case 1:
                                case 3:
                                    value = BitConverter.GetBytes(Convert.ToSingle(stack2.Pop().ToString()));
                                    break;
                            }
                            condition.Value = value;

                            if (condition.ConditionType == 1)
                            {
                                condition.ConditionLeft = PWGetCondition(s2);
                                condition.SubNodeL = Common.GetSubNodeL(condition.OperID);
                                condition.ConditionRight = PWGetCondition(str);
                                condition.SubNodeR = Common.GetSubNodeR(condition.OperID);
                            }

                            if (condition.ConditionType == 2)
                            {
                                condition.ConditionRight = PWGetCondition(str);
                                condition.SubNodeL = Common.GetSubNodeL(condition.OperID);
                            }

                            return condition;
                        }

                        stack1.Push(text);
                        length++;
                    }
                }

                text = length < s.Length ? s.Substring(length, 1) : "";
            }

            return null;
        }

        internal void PWProcedureList()
        {
            label_Param2.BackColor = Color.Transparent;
            switch (comboBox_Proc.SelectedIndex)
            {
                // Attack(int unk)
                case 0:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Attack;
                    label_Param1.Text = Resources.AttackParam;
                    break;

                // Cast_Skill(int skill_id, int skill_lvl)
                case 1:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Cast_Skill;
                    label_Param1.Text = Resources.SkillID;
                    label_Param2.Text = Resources.SkillLevel;
                    break;

                // Broadcast_Message(int byteCount, byte[] message)
                case 2:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Broadcast_Message;
                    label_Param1.Text = Resources.ByteCount;
                    label_Param2.Text = Resources.Message;
                    label_Param2.BackColor = Color.Gold;
                    break;

                // Reset_Aggro()
                case 3:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Reset_Aggro;
                    break;

                // Exec_ActionSet(int actionset_id)
                case 4:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Execute_ActionSet;
                    label_Param1.Text = Resources.ActionSetID;
                    break;

                // Disable_ActionSet(int actionset_id)
                case 5:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Disable_ActionSet;
                    label_Param1.Text = Resources.ActionSetID;
                    break;

                // Enable_ActionSet(int actionset_id)
                case 6:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Enable_ActionSet;
                    label_Param1.Text = Resources.ActionSetID;
                    break;

                // Create_Timer(int timerID, int delay, int cycles)
                case 7:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Create_Timer;
                    label_Param1.Text = Resources.TimerID;
                    label_Param2.Text = Resources.Delay;
                    label_Param3.Text = Resources.Cycles;
                    break;

                // Delete_Timer(int timerID)
                case 8:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Delete_Timer;
                    label_Param1.Text = Resources.TimerID;
                    break;

                // Flee()
                case 9:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Flee;
                    break;

                // Be_Taunted()
                case 10:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Be_Taunted;
                    break;

                // Fade_Target()
                case 11:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Fade_Target;
                    break;

                // Fade_Aggro()
                case 12:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Fade_Aggro;
                    break;

                // Break()
                case 13:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Break;
                    break;

                // NPC_Generator(int triggerID, int ctrlParam)
                case 14:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.NPC_Generator;
                    label_Param1.Text = Resources.TriggerID;
                    label_Param2.Text = Resources.Control;
                    break;

                // Initialize_Public_Counter
                case 15:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Initialize_Public_Counter;
                    label_Param1.Text = Resources.Unknown;
                    label_Param2.Text = Resources.Unknown;
                    label_Param3.Text = Resources.Unknown;
                    break;

                // Increment_Public_Counter
                case 16:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Increment_Public_Counter;
                    label_Param1.Text = Resources.Unknown;
                    label_Param2.Text = Resources.Unknown;
                    break;

                // Player_Aimed_NPC_Spawn
                case 17:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Player_Aimed_NPC_Spawn;
                    label_Param1.Text = Resources.ElementsID;
                    label_Param2.Text = Resources.TimeInterval;
                    label_Param3.Text = Resources.Calls;
                    label_Param4.Text = Resources.Survival;
                    label_Param5.Text = Resources.MobName;
                    label_Param6.Text = Resources.RefreshRange;
                    label_Param7.Text = Resources.Unknown;
                    break;

                // Change_Path
                case 18:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Change_Path;
                    label_Param1.Text = Resources.Unknown;
                    label_Param2.Text = Resources.Unknown;
                    label_Param3.Text = Resources.Unknown;
                    label_Param4.Text = Resources.Unknown;
                    break;

                // Play_Action
                case 19:
                    groupBox_ProcParams.Text = Resources.AddProcedure + Resources.Play_Action;
                    label_Param1.Text = Resources.Unknown;
                    label_Param2.Text = Resources.Unknown;
                    label_Param3.Text = Resources.Unknown;
                    label_Param4.Text = Resources.Unknown;
                    break;
            }
        }

        private static void PWSaveCondition(Condition c, BinaryWriter bw)
        {
            bw.Write(c.OperID);
            bw.Write(c.ArgBytes);
            bw.Write(c.Value);
            bw.Write(c.ConditionType);

            if (c.ConditionType == 1)
            {
                PWSaveCondition(c.ConditionLeft, bw);
                bw.Write(c.SubNodeL);

                if (c.SubNodeL == 2)
                {
                    PWSaveCondition(c.ConditionRight, bw);
                    bw.Write(c.SubNodeR);
                }
            }

            if (c.ConditionType != 2) return;

            PWSaveCondition(c.ConditionRight, bw);
            bw.Write(c.SubNodeL);
        }

        private static void PWWriteParameters(int type, IList<object> parameters, BinaryWriter bw)
        {
            switch (type)
            {
                // Type 0 - Attack(int unk)
                case 0:
                    bw.Write((int)parameters[0]);
                    break;

                // Type 1 - Cast_Skill(int skill_id, int skill_lvl)
                case 1:
                    bw.Write((int)parameters[0]);
                    bw.Write((int)parameters[1]);
                    break;

                // Type 2 - Broadcast_Message(int byteCount, byte[] message)
                case 2:
                    bw.Write((int)parameters[0]);
                    bw.Write((byte[])parameters[1]);
                    break;

                // Type 3 - Reset_Aggro()
                // no parameters...
                case 3:
                    break;

                // Type 4 - Exec_ActionSet(int actionset_id)
                case 4:

                // Type 5 - Disable_ActionSet(int actionset_id)
                case 5:

                // Type 6 - Enable_ActionSet(int actionset_id)
                case 6:
                    bw.Write((int)parameters[0]);
                    break;

                // Type 7 - Create_Timer(int timerID, int delay, int cycles)
                case 7:
                    bw.Write((int)parameters[0]);
                    bw.Write((int)parameters[1]);
                    bw.Write((int)parameters[2]);
                    break;

                // Type 8 - Delete_Timer(int timerID)
                case 8:
                    bw.Write((int)parameters[0]);
                    break;

                // Type 9 - Flee()
                // no parameters...
                case 9:

                // Type 10 - Be_Taunted()
                // no parameters...
                case 10:

                // Type 11 - Fade_Target()
                // no parameters...
                case 11:

                // Type 12 - Fade_Aggro()
                // no parameters...
                case 12:

                // Tpye 13 - Break()
                // no parameters...
                case 13:
                    break;

                // Type 14 - NPC_Generator(int triggerID, int ctrlParam)
                case 14:
                    bw.Write((int)parameters[0]);
                    bw.Write((int)parameters[1]);
                    break;

                // Type 15 - Initialize_Public_Counter(int x, int y, int z)
                case 15:
                    bw.Write((int)parameters[0]);
                    bw.Write((int)parameters[1]);
                    bw.Write((int)parameters[2]);
                    break;

                // Type 16 - Increment_Public_Counter(int x, int y)
                case 16:
                    bw.Write((int)parameters[0]);
                    bw.Write((int)parameters[1]);
                    break;

                // Type 17 - Player_Aimed_NPC_Spawn(int elementsID, int unknown, int unknown, int unknown, int unknown, int unknown)
                case 17:
                    bw.Write((int)parameters[0]);
                    bw.Write((int)parameters[1]);
                    bw.Write((int)parameters[2]);
                    bw.Write((int)parameters[3]);
                    bw.Write((int)parameters[4]);
                    bw.Write((int)parameters[5]);
                    break;

                // Type 18 - Change_Path(int w, int x, int y, int z)
                case 18:
                    bw.Write((int)parameters[0]);
                    bw.Write((int)parameters[1]);
                    bw.Write((int)parameters[2]);
                    bw.Write((int)parameters[3]);
                    break;

                // Type 19 - Play_Action(sting w, int x, int y, int z)
                case 19:
                    bw.Write((byte[])parameters[0]);
                    bw.Write((int)parameters[1]);
                    bw.Write((int)parameters[2]);
                    bw.Write((int)parameters[3]);
                    break;
            }
        }

        //*************************************************************
        //                    Genernal Methods
        //*************************************************************

        private void ListBoxControllerSelectedIndexChanged(object sender, EventArgs e)
        {
            label_Param2.BackColor = Color.Transparent;
            ClearParams();

            if (AI == null || listBox_Controller.SelectedIndex <= -1) return;

            var cSelectedIndex = listBox_Controller.SelectedIndex;
            var actionSet = AI.ActionController[cSelectedIndex].ActionSet;

            listBox_ActionSet.Items.Clear();
            textBox_CtrlID.Text = listBox_Controller.SelectedItem.ToString();

            foreach (var aSet in actionSet)
            {
                var iD = aSet.ID;
                listBox_ActionSet.Items.Add("[" + iD.ToString(CultureInfo.InvariantCulture) + "] " + aSet.Name);
                textBox_CtrlID.Text = AI.ActionController[cSelectedIndex].ID.ToString(CultureInfo.InvariantCulture);
            }

            textBox_ActionID.Clear();
            textBox_Flag1.Clear();
            textBox_Flag2.Clear();
            textBox_Flag3.Clear();
            textBox_ActionName.Clear();
            textBox_Condition.Clear();
            listBox_Procedure.Items.Clear();
        }

        private void ListBoxActionSetSelectedIndexChanged(object sender, EventArgs e)
        {
            label_Param2.BackColor = Color.Transparent;
            ClearParams();

            if (AI == null || listBox_Controller.SelectedIndex <= -1 || listBox_ActionSet.SelectedIndex <= -1) return;

            var cSelectedIndex = listBox_Controller.SelectedIndex;
            var asSelectedIndex = listBox_ActionSet.SelectedIndex;

            // Jade Dynasty
            if (JDSelected) textBox_Condition.Text = JDConditionExpression(AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Condition);

            // Perfect World
            if (PWSelected) textBox_Condition.Text = PWConditionExpression(AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Condition);

            listBox_Procedure.Items.Clear();

            for (var i = 0; i < AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure.Length; i++)
            {
                // Jade Dynasty
                if (JDSelected) listBox_Procedure.Items.Add("[" + i.ToString(CultureInfo.InvariantCulture) + "] " +
                    JDProcedureExpression(AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[i],
                    AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Version));

                // Perfect World
                if (PWSelected) listBox_Procedure.Items.Add("[" + i.ToString(CultureInfo.InvariantCulture) + "] " +
                    PWProcedureExpression(AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[i]));

                textBox_ActionID.Text = AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].ID.ToString(CultureInfo.InvariantCulture);
                textBox_Flag1.Text = AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Flags[0].ToString(CultureInfo.InvariantCulture);
                textBox_Flag2.Text = AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Flags[1].ToString(CultureInfo.InvariantCulture);
                textBox_Flag3.Text = AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Flags[2].ToString(CultureInfo.InvariantCulture);
                textBox_ActionName.Text = AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Name.ToString(CultureInfo.InvariantCulture);
            }
        }

        private void ListBoxProcedureSelectedIndexChanged(object sender, EventArgs e)
        {
            groupBox_ProcParams.Text = Resources.ProcedureParameters;
            ClearParams();

            if (AI == null || listBox_Controller.SelectedIndex <= -1 || listBox_ActionSet.SelectedIndex <= -1 ||
                listBox_Procedure.SelectedIndex <= -1) return;

            var cSelectedIndex = listBox_Controller.SelectedIndex;
            var asSelectedIndex = listBox_ActionSet.SelectedIndex;
            var pSelectedIndex = listBox_Procedure.SelectedIndex;

            int timerID;
            int delay;
            int cycles;
            int unk1;
            int actionID;
            int value;
            int amt;

            switch (AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Type)
            {
                // Type 0 - Attack(int unk)
                case 0:
                    groupBox_ProcParams.Text = Resources.Attack;
                    label_Param1.Text = Resources.AttackParam;

                    var param1 = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                    textBox_Param1.Text = param1.ToString(CultureInfo.InvariantCulture);
                    break;

                // Cast_Skill(int skill_id, int skill_lvl)
                case 1:
                    groupBox_ProcParams.Text = Resources.Cast_Skill;
                    label_Param1.Text = Resources.SkillID;
                    label_Param2.Text = Resources.SkillLevel;
                    label_Param2.BackColor = Color.Transparent;

                    var skillID = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                    textBox_Param1.Text = skillID.ToString(CultureInfo.InvariantCulture);

                    var skillLvl = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[1];
                    textBox_Param2.Text = skillLvl.ToString(CultureInfo.InvariantCulture);
                    break;

                // Broadcast_Message(int byteCount, byte[] message)
                case 2:
                    groupBox_ProcParams.Text = Resources.Broadcast_Message;
                    label_Param1.Text = Resources.ByteCount;
                    label_Param2.Text = Resources.Message;
                    label_Param2.BackColor = Color.Gold;

                    var byteCount = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                    textBox_Param1.Text = byteCount.ToString(CultureInfo.InvariantCulture);
                    textBox_Param2.Text = Encoding.Unicode.GetString((byte[])AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].
                        Procedure[pSelectedIndex].Parameter[1]);
                    break;

                // Reset_Aggro()
                case 3:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.Reset_Aggro;
                    break;

                // Execute_ActionSet(int ActionSetID)
                case 4:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.Execute_ActionSet;
                    label_Param1.Text = Resources.ActionSetID;

                    actionID = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                    textBox_Param1.Text = actionID.ToString(CultureInfo.InvariantCulture);
                    break;

                // Disable_ActionSet(int ActionSetID)
                case 5:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.Disable_ActionSet;
                    label_Param1.Text = Resources.ActionSetID;
                    actionID = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                    textBox_Param1.Text = actionID.ToString(CultureInfo.InvariantCulture);
                    break;

                // Enable_ActionSet(int ActionSetID)
                case 6:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.Enable_ActionSet;
                    label_Param1.Text = Resources.ActionSetID;
                    actionID = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                    textBox_Param1.Text = actionID.ToString(CultureInfo.InvariantCulture);
                    break;

                // Create_Timer(int TimerID, int Delay, int Cycles)
                case 7:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.Create_Timer;
                    label_Param1.Text = Resources.TimerID;
                    label_Param2.Text = Resources.Delay;
                    label_Param3.Text = Resources.Cycles;

                    timerID = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                    textBox_Param1.Text = timerID.ToString(CultureInfo.InvariantCulture);

                    delay = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[1];
                    textBox_Param2.Text = delay.ToString(CultureInfo.InvariantCulture);

                    cycles = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[2];
                    textBox_Param3.Text = cycles.ToString(CultureInfo.InvariantCulture);
                    break;

                // Delete_Timer(int TimerID)
                case 8:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.Delete_Timer;
                    label_Param1.Text = Resources.TimerID;

                    var num11 = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                    textBox_Param1.Text = num11.ToString(CultureInfo.InvariantCulture);
                    break;

                // Flee()
                case 9:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.Flee;
                    break;

                // Be_Taunted
                case 10:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.Be_Taunted;
                    break;

                // Fade_Target()
                case 11:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.Fade_Target;
                    break;

                // Fade_Aggro()
                case 12:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.Fade_Aggro;
                    break;

                // Break()
                case 13:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.Break;
                    break;

                // NPC_Generator(int TriggerID, int CtrlParam)
                case 14:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.NPC_Generator;

                    label_Param1.Text = Resources.TriggerID;
                    label_Param2.Text = Resources.Control;

                    var triggerID = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                    textBox_Param1.Text = triggerID.ToString(CultureInfo.InvariantCulture);

                    var ctrlParam = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[1];
                    textBox_Param2.Text = ctrlParam.ToString(CultureInfo.InvariantCulture);
                    break;

                case 15:
                    label_Param2.BackColor = Color.Transparent;

                    // Summon_Mob(int ElementsID, int TimeInterval, int Calls, int Survival, string MobName, int RefreshRange, int Unknown)
                    if (JDSelected)
                    {
                        groupBox_ProcParams.Text = Resources.Summon_Mob;
                        label_Param1.Text = Resources.ElementsID;
                        label_Param2.Text = Resources.TimeInterval;
                        label_Param3.Text = Resources.Calls;
                        label_Param5.Text = Resources.Survival;
                        label_Param5.Text = Resources.MobName;
                        label_Param6.Text = Resources.RefreshRange;
                        label_Param7.Text = Resources.Unknown;

                        var elementsID = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                        textBox_Param1.Text = elementsID.ToString(CultureInfo.InvariantCulture);

                        var timeInt = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[1];
                        textBox_Param2.Text = timeInt.ToString(CultureInfo.InvariantCulture);

                        var calls = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[2];
                        textBox_Param3.Text = calls.ToString(CultureInfo.InvariantCulture);

                        var survival = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[3];
                        textBox_Param4.Text = survival.ToString(CultureInfo.InvariantCulture);

                        textBox_Param5.Text = Encoding.Unicode.GetString((byte[])AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].
                            Procedure[pSelectedIndex].Parameter[4]);

                        var refreshRange = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[5];
                        textBox_Param6.Text = refreshRange.ToString(CultureInfo.InvariantCulture);

                        var unknown = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[6];
                        textBox_Param7.Text = unknown.ToString(CultureInfo.InvariantCulture);
                    }

                    // Initialize_Public_Counter(int Unknown1, int Unknown2, int Unknown3)
                    if (PWSelected)
                    {
                        label_Param2.BackColor = Color.Transparent;
                        groupBox_ProcParams.Text = Resources.Initialize_Public_Counter;
                        label_Param1.Text = Resources.Unknown;
                        label_Param2.Text = Resources.Unknown;
                        label_Param3.Text = Resources.Unknown;

                        var x = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                        textBox_Param1.Text = x.ToString(CultureInfo.InvariantCulture);

                        var y = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[1];
                        textBox_Param2.Text = y.ToString(CultureInfo.InvariantCulture);

                        var z = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[2];
                        textBox_Param3.Text = z.ToString(CultureInfo.InvariantCulture);
                    }
                    break;

                case 16:
                    label_Param2.BackColor = Color.Transparent;

                    // Unknown16(int Unknown)
                    if (JDSelected)
                    {
                        groupBox_ProcParams.Text = Resources.Unknown16;
                        label_Param1.Text = Resources.Unknown;

                        unk1 = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                        textBox_Param1.Text = unk1.ToString(CultureInfo.InvariantCulture);
                    }

                    // Increment_Public_Counter(int Unknown1, int Unknown2)
                    if (PWSelected)
                    {
                        label_Param2.BackColor = Color.Transparent;
                        groupBox_ProcParams.Text = Resources.Increment_Public_Counter;
                        label_Param1.Text = Resources.Unknown;
                        label_Param2.Text = Resources.Unknown;

                        var x = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                        textBox_Param1.Text = x.ToString(CultureInfo.InvariantCulture);

                        var y = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[1];
                        textBox_Param2.Text = y.ToString(CultureInfo.InvariantCulture);
                    }
                    break;

                case 17:
                    label_Param2.BackColor = Color.Transparent;

                    // Set_Path(int PathID)
                    // if (version == 11) Set_Path(int PathID, int v11Path)
                    if (JDSelected)
                    {
                        groupBox_ProcParams.Text = Resources.Set_Path;
                        label_Param1.Text = Resources.PathID;

                        var pathID = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                        textBox_Param1.Text = pathID.ToString(CultureInfo.InvariantCulture);

                        if (AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Version == 11)
                        {
                            label_Param2.Text = Resources.v11Path;

                            var v11Path = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[1];
                            textBox_Param2.Text = v11Path.ToString(CultureInfo.InvariantCulture);
                        }
                    }

                    // Player_Aimed_NPC_Spawn(int ElementsID, int TimeInterval, int Calls, int Survival, string MobName, int RefreshRange, int Unknown)
                    if (PWSelected)
                    {
                        label_Param2.BackColor = Color.Transparent;
                        groupBox_ProcParams.Text = Resources.Player_Aimed_NPC_Spawn;
                        label_Param1.Text = Resources.ElementsID;
                        label_Param2.Text = Resources.TimeInterval;
                        label_Param3.Text = Resources.Calls;
                        label_Param5.Text = Resources.Survival;
                        label_Param5.Text = Resources.MobName;
                        label_Param6.Text = Resources.RefreshRange;
                        label_Param7.Text = Resources.Unknown;

                        var elementsID = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                        textBox_Param1.Text = elementsID.ToString(CultureInfo.InvariantCulture);

                        var timeInt = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[1];
                        textBox_Param2.Text = timeInt.ToString(CultureInfo.InvariantCulture);

                        var calls = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[2];
                        textBox_Param3.Text = calls.ToString(CultureInfo.InvariantCulture);

                        var survival = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[3];
                        textBox_Param4.Text = survival.ToString(CultureInfo.InvariantCulture);

                        textBox_Param5.Text = Encoding.Unicode.GetString((byte[])AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].
                            Procedure[pSelectedIndex].Parameter[4]);

                        var refreshRange = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[5];
                        textBox_Param6.Text = refreshRange.ToString(CultureInfo.InvariantCulture);

                        var unknown = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[6];
                        textBox_Param7.Text = unknown.ToString(CultureInfo.InvariantCulture);
                    }
                    break;


                case 18:
                    label_Param2.BackColor = Color.Transparent;

                    // Disappear()
                    if (JDSelected) groupBox_ProcParams.Text = Resources.Disappear;

                    // Change_Path(int Unknown1, int Unknown2, int Unknown3)
                    if (PWSelected)
                    {
                        groupBox_ProcParams.Text = Resources.Change_Path;
                        label_Param1.Text = Resources.Unknown;
                        label_Param2.Text = Resources.Unknown;
                        label_Param3.Text = Resources.Unknown;

                        var x = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                        textBox_Param1.Text = x.ToString(CultureInfo.InvariantCulture);

                        var y = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[1];
                        textBox_Param2.Text = y.ToString(CultureInfo.InvariantCulture);

                        var z = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[2];
                        textBox_Param3.Text = z.ToString(CultureInfo.InvariantCulture);
                    }
                    break;

                case 19:
                    label_Param2.BackColor = Color.Transparent;

                    // N/A
                    if (JDSelected) groupBox_ProcParams.Text = Resources.NA;

                    // Play_Action(int unknown1, int unknown2, int unknown3)
                    if (PWSelected)
                    {
                        groupBox_ProcParams.Text = Resources.Play_Action;
                        label_Param1.Text = Resources.Unknown;
                        label_Param2.Text = Resources.Unknown;
                        label_Param3.Text = Resources.Unknown;

                        var x = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                        textBox_Param1.Text = x.ToString(CultureInfo.InvariantCulture);

                        var y = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[1];
                        textBox_Param2.Text = y.ToString(CultureInfo.InvariantCulture);

                        var z = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[2];
                        textBox_Param3.Text = z.ToString(CultureInfo.InvariantCulture);
                    }
                    break;

                // N/A
                case 20:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.NA;
                    break;

                // Respawn()
                case 21:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.Respawn;
                    break;

                // Set_Value(int Value, int amt)
                case 22:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.Set_Value;
                    label_Param1.Text = Resources.Value;
                    label_Param2.Text = Resources.EQUAL;

                    value = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                    textBox_Param1.Text = value.ToString(CultureInfo.InvariantCulture);

                    amt = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[1];
                    textBox_Param2.Text = amt.ToString(CultureInfo.InvariantCulture);
                    break;

                // Add_Value(int value, int amt)
                case 23:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.Add_Value;
                    label_Param1.Text = Resources.Value;
                    label_Param2.Text = Resources.PLUS;

                    value = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                    textBox_Param1.Text = value.ToString(CultureInfo.InvariantCulture);

                    amt = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[1];
                    textBox_Param2.Text = amt.ToString(CultureInfo.InvariantCulture);
                    break;

                // N/A
                case 24:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.NA;
                    break;

                // Set_Mob_Attribute(int mobID, int cycles, int unk1, int name, int unk2)
                case 25:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.Set_Mob_Attribute;
                    label_Param1.Text = Resources.MobID;
                    label_Param2.Text = Resources.Cycles;
                    label_Param3.Text = Resources.Unknown;
                    label_Param5.Text = Resources.MobID;
                    label_Param5.Text = Resources.Unknown;

                    var mobID = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                    textBox_Param1.Text = mobID.ToString(CultureInfo.InvariantCulture);

                    cycles = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[1];
                    textBox_Param2.Text = cycles.ToString(CultureInfo.InvariantCulture);

                    unk1 = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[2];
                    textBox_Param3.Text = unk1.ToString(CultureInfo.InvariantCulture);

                    var name = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[3];
                    textBox_Param4.Text = name.ToString(CultureInfo.InvariantCulture);

                    var unk2 = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[4];
                    textBox_Param5.Text = unk2.ToString(CultureInfo.InvariantCulture);
                    break;

                // Drop_WarSoul(int itemID, int calls, int cycles)
                case 26:
                    label_Param2.BackColor = Color.Transparent;
                    groupBox_ProcParams.Text = Resources.Drop_WarSoul;
                    label_Param1.Text = Resources.ItemID;
                    label_Param2.Text = Resources.Calls;
                    label_Param3.Text = Resources.Cycles;

                    timerID = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[0];
                    textBox_Param1.Text = timerID.ToString(CultureInfo.InvariantCulture);

                    delay = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[1];
                    textBox_Param2.Text = delay.ToString(CultureInfo.InvariantCulture);

                    cycles = (int)AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter[2];
                    textBox_Param3.Text = cycles.ToString(CultureInfo.InvariantCulture);
                    break;
            }

            // Type Target
            var target = AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Target;

            // Jade Dynasty
            if (JDSelected) textBox_ParamTarget.Text = JDProcedureTarget(target);

            // Perfect World
            if (PWSelected && target == 6)
                textBox_ParamTarget.Text = PWProcedureTarget(target, AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].
                    Procedure[pSelectedIndex].TargetParams);
            else textBox_ParamTarget.Text = PWProcedureTarget(target, null);
        }

        private void LabelParam2Click(object sender, EventArgs e)
        {
            if (label_Param2.Text == Resources.Message)
                panel_MsgHelper.Visible = true;
        }

        private void LabelParamTargetClick(object sender, EventArgs e)
        {
            panel_TargetHelper.Visible = true;
        }

        private void ButtonAddCtrlClick(object sender, EventArgs e)
        {
            if (AI == null)
            {
                MessageBox.Show(Resources.OpenAIPolicyFirst + Resources.AddAController);
                return;
            }

            if (AI != null && textBox_CtrlID.Text != "")
            {
                var acCount = AI.ActionControllerCount;

                if (!Common.IsNumber(textBox_CtrlID.Text))
                {
                    MessageBox.Show(Resources.NoCtrlIDEntered);
                    return;
                }

                var ctrlID = Convert.ToInt32(textBox_CtrlID.Text);

                for (var i = 0; i < acCount; i++)
                {
                    if (ctrlID != AI.ActionController[i].ID || ctrlID <= 0) continue;

                    MessageBox.Show(Resources.ControllerIDExists);
                    return;
                }

                acCount++;
                var aIPolicy = new AIPolicy();

                aIPolicy.Signature = 0;
                aIPolicy.ActionControllerCount = acCount;
                aIPolicy.ActionController = new ActionController[acCount];

                for (var j = 0; j < aIPolicy.ActionController.Length - 1; j++)
                {
                    aIPolicy.ActionController[j] = AI.ActionController[j];
                    aIPolicy.ActionController[j].Signature = AI.ActionController[j].Signature;
                    aIPolicy.ActionController[j].ID = AI.ActionController[j].ID;
                    aIPolicy.ActionController[j].ActionSetsCount = AI.ActionController[j].ActionSetsCount;
                    aIPolicy.ActionController[j].ActionSet = AI.ActionController[j].ActionSet;
                }

                AI = aIPolicy;

                AI.ActionController[acCount - 1] = new ActionController();
                AI.ActionController[acCount - 1].Signature = 0;
                AI.ActionController[acCount - 1].ActionSetsCount = 0;

                AI.ActionController[acCount - 1].ActionSet = new ActionSet[aIPolicy.ActionController[acCount - 1].ActionSetsCount];
                AI.ActionController[acCount - 1].ID = ctrlID;
                listBox_Controller.Items.Clear();

                for (var k = 0; k < AI.ActionControllerCount; k++)
                {
                    var iD = AI.ActionController[k].ID;
                    listBox_Controller.Items.Add(iD.ToString(CultureInfo.InvariantCulture));
                }

                listBox_ActionSet.Items.Clear();
                textBox_Condition.Clear();
                listBox_Procedure.Items.Clear();
            }

            MessageBox.Show(Resources.ControllerWithID + textBox_CtrlID.Text + Resources.AddedEndTable);
        }

        private void ButtonDelCtrlClick(object sender, EventArgs e)
        {
            if (AI == null)
            {
                MessageBox.Show(Resources.OpenAIPolicyFirst + Resources.DeleteAController);
                return;
            }

            if (AI != null && textBox_CtrlID.Text != "")
            {
                var actionControllerCount = AI.ActionControllerCount;
                var ctrlID = -1;

                if (!Common.IsNumber(textBox_CtrlID.Text))
                {
                    MessageBox.Show(Resources.NoCtrlIDEntered);
                    return;
                }

                var delCtrlID = Convert.ToInt32(textBox_CtrlID.Text);

                for (var i = 0; i < actionControllerCount; i++)
                    if (delCtrlID == AI.ActionController[i].ID) ctrlID = i;

                if (ctrlID < 0)
                {
                    MessageBox.Show(Resources.ControllerIDNoExists);
                    return;
                }

                var aIPolicy = new AIPolicy();
                aIPolicy.Signature = 0;
                aIPolicy.ActionControllerCount = actionControllerCount - 1;

                var aIPolicy2 = aIPolicy;
                aIPolicy2.ActionController = new ActionController[aIPolicy2.ActionControllerCount];

                for (var j = 0; j < aIPolicy.ActionController.Length; j++)
                {
                    if (j < ctrlID) aIPolicy.ActionController[j] = AI.ActionController[j];
                    if (j >= ctrlID) aIPolicy.ActionController[j] = AI.ActionController[j + 1];
                }

                AI = aIPolicy;
                listBox_Controller.Items.Clear();

                for (var k = 0; k < AI.ActionControllerCount; k++)
                    listBox_Controller.Items.Add(AI.ActionController[k].ID.ToString(CultureInfo.InvariantCulture));

                listBox_ActionSet.Items.Clear();
                textBox_Condition.Clear();
                listBox_Procedure.Items.Clear();
            }

            MessageBox.Show(Resources.ControllerWithID + textBox_CtrlID.Text + Resources.BeenDeleted);
        }

        private void ButtonAddActionClick(object sender, EventArgs e)
        {
            var actionID = 0;

            if (AI == null)
            {
                MessageBox.Show(Resources.OpenAIPolicyFirst + Resources.AddAnActionSet);
                return;
            }

            if (listBox_Controller.SelectedIndex == -1) return;

            if (textBox_ActionName.Text == "")
            {
                MessageBox.Show(Resources.EnterNameForActionSet);
                return;
            }

            var cSelectedIndex = listBox_Controller.SelectedIndex;
            var asSelectedIndex = listBox_ActionSet.SelectedIndex;
            var actionSetCount = AI.ActionController[cSelectedIndex].ActionSetsCount;

            if (Common.IsNumber(textBox_ActionID.Text))
            {
                actionID = Convert.ToInt32(textBox_ActionID.Text);

                for (var i = 0; i < actionSetCount; i++)
                {
                    if (actionID != AI.ActionController[cSelectedIndex].ActionSet[i].ID) continue;

                    MessageBox.Show(Resources.TheActionSetID + actionID + Resources.AlreadyExists);
                    return;
                }
            }

            if (asSelectedIndex == -1) asSelectedIndex = actionSetCount;

            var actionSet = new ActionSet[actionSetCount + 1];

            for (var j = 0; j <= actionSetCount; j++)
            {
                if (j < asSelectedIndex) actionSet[j] = AI.ActionController[cSelectedIndex].ActionSet[j];
                if (j > asSelectedIndex) actionSet[j] = AI.ActionController[cSelectedIndex].ActionSet[j - 1];
            }

            actionSet[asSelectedIndex] = new ActionSet();
            actionSet[asSelectedIndex].Version = 11;

            if (textBox_ActionID.Text == "")
            {
                var asCount = actionSetCount;
                for (var k = 0; k < actionSetCount; k++)
                    if (asCount < AI.ActionController[cSelectedIndex].ActionSet[k].ID)
                        asCount = AI.ActionController[cSelectedIndex].ActionSet[k].ID;

                for (var x = 0; x <= asCount; x++)
                {
                    for (var y = 0; y < actionSetCount; y++)
                        if (x == AI.ActionController[cSelectedIndex].ActionSet[y].ID)
                            actionSet[asSelectedIndex].ID = -1;

                    if (actionSet[asSelectedIndex].ID != -1)
                    {
                        actionSet[asSelectedIndex].ID = x;
                        break;
                    }

                    actionSet[asSelectedIndex].ID = x;
                }
            }
            else
                actionSet[asSelectedIndex].ID = actionID;

            var tmpFlags = new byte[3];
            tmpFlags[0] = 1;
            var flags = tmpFlags;

            actionSet[asSelectedIndex].Flags = flags;
            actionSet[asSelectedIndex].Name = textBox_ActionName.Text;
            actionSet[asSelectedIndex].Condition = new Condition();
            actionSet[asSelectedIndex].Condition.OperID = 3;
            actionSet[asSelectedIndex].Condition.ArgBytes = 4;

            var value = new byte[] { 0, 0, 128, 63 };

            actionSet[asSelectedIndex].Condition.Value = value;
            actionSet[asSelectedIndex].Condition.SubNodeL = 0;
            actionSet[asSelectedIndex].Condition.SubNodeR = 0;
            actionSet[asSelectedIndex].Condition.ConditionType = 3;
            actionSet[asSelectedIndex].ProcedureCount = 1;

            actionSet[asSelectedIndex].Procedure = new Procedure[1];
            actionSet[asSelectedIndex].Procedure[0] = new Procedure();
            actionSet[asSelectedIndex].Procedure[0].Type = 2;

            var unicode = Encoding.Unicode;
            var rageMsg = unicode.GetBytes("RaGEZONE Forums - http://Forum.RaGEZONE.com");
            var msgSize = rageMsg.Length + 2;
            var mess = new byte[msgSize];

            Array.Copy(rageMsg, mess, rageMsg.Length);
            mess[rageMsg.Length] = 0;
            mess[rageMsg.Length + 1] = 0;

            var parameter = new object[] { msgSize, mess };

            actionSet[asSelectedIndex].Procedure[0].Parameter = parameter;
            actionSet[asSelectedIndex].Procedure[0].Target = 0;
            AI.ActionController[cSelectedIndex].ActionSetsCount = AI.ActionController[cSelectedIndex].ActionSetsCount + 1;
            AI.ActionController[cSelectedIndex].ActionSet = actionSet;

            listBox_ActionSet.Items.Clear();

            foreach (var t in AI.ActionController[cSelectedIndex].ActionSet)
                listBox_ActionSet.Items.Add("[" + t.ID.ToString(CultureInfo.InvariantCulture) + "] " + t.Name);

            textBox_Condition.Clear();
            listBox_Procedure.Items.Clear();
        }

        private void ButtonDelActionClick(object sender, EventArgs e)
        {
            if (AI == null)
            {
                MessageBox.Show(Resources.OpenAIPolicyFirst + Resources.DeleteAnActionSet);
                return;
            }

            if (listBox_Controller.SelectedIndex == -1) return;

            var cSelectedIndex = listBox_Controller.SelectedIndex;
            var asSelectedIndex = listBox_ActionSet.SelectedIndex;
            var actionSetCount = AI.ActionController[cSelectedIndex].ActionSetsCount;

            if (asSelectedIndex == -1)
            {
                MessageBox.Show(Resources.NoActionSetSelectedDelete);
                return;
            }

            var actionSet = new ActionSet[actionSetCount - 1];

            for (var i = 0; i < actionSetCount - 1; i++)
            {
                if (i < asSelectedIndex) actionSet[i] = AI.ActionController[cSelectedIndex].ActionSet[i];
                if (i >= asSelectedIndex) actionSet[i] = AI.ActionController[cSelectedIndex].ActionSet[i + 1];
            }

            AI.ActionController[cSelectedIndex].ActionSetsCount = AI.ActionController[cSelectedIndex].ActionSetsCount - 1;
            AI.ActionController[cSelectedIndex].ActionSet = actionSet;

            listBox_ActionSet.Items.Clear();

            foreach (var t in AI.ActionController[cSelectedIndex].ActionSet)
                listBox_ActionSet.Items.Add("[" + t.ID.ToString(CultureInfo.InvariantCulture) + "] " + t.Name);

            textBox_Condition.Clear();
            listBox_Procedure.Items.Clear();
        }

        private void ButtonEditActionClick(object sender, EventArgs e)
        {
            if (AI == null)
            {
                MessageBox.Show(Resources.OpenAIPolicyFirst + Resources.EditAnActionSet);
                return;
            }

            var cSelectedIndex = listBox_Controller.SelectedIndex;
            var asSelectedIndex = listBox_ActionSet.SelectedIndex;

            if (listBox_Controller.SelectedIndex != -1 && listBox_ActionSet.SelectedIndex != -1)
            {
                if (textBox_ActionName.Text == "")
                {
                    MessageBox.Show(Resources.EnterNewActionSetName);
                    return;
                }

                AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Flags[0] = Convert.ToByte(textBox_Flag1.Text);
                AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Flags[1] = Convert.ToByte(textBox_Flag2.Text);
                AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Flags[2] = Convert.ToByte(textBox_Flag3.Text);
                AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Name = textBox_ActionName.Text;
            }

            listBox_ActionSet.Items.Clear();

            foreach (var t in AI.ActionController[cSelectedIndex].ActionSet)
                listBox_ActionSet.Items.Add("[" + t.ID.ToString(CultureInfo.InvariantCulture) + "] " + t.Name);

            textBox_Condition.Clear();
            listBox_Procedure.Items.Clear();
        }

        private void ButtonAddProcClick(object sender, EventArgs e)
        {
            if (AI == null)
            {
                MessageBox.Show(Resources.OpenAIPolicyFirst + Resources.AddAProcedure);
                return;
            }

            var cSelectedIndex = listBox_Controller.SelectedIndex;
            var asSelectedIndex = listBox_ActionSet.SelectedIndex;
            object[] pArray = null;

            if (comboBox_Proc.SelectedIndex != -1 && asSelectedIndex != -1)
            {
                // Jade Dynasty
                if (JDSelected) pArray = JDGetParameters(comboBox_Proc.SelectedIndex,
                    AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Version);

                // Perfect World
                if (PWSelected) pArray = PWGetParameters(comboBox_Proc.SelectedIndex);

                if (pArray == null) return;

                var pSelectedIndex = listBox_Procedure.SelectedIndex;
                var procedure = AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure;

                AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].ProcedureCount =
                    AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].ProcedureCount + 1;

                var pCount = AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].ProcedureCount;
                AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure = new Procedure[pCount];

                pCount--;
                if (pSelectedIndex == -1) pSelectedIndex = pCount;

                for (var i = 0; i <= pCount; i++)
                {
                    AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[i] = new Procedure();

                    if (i < pSelectedIndex)
                    {
                        AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[i].Type = procedure[i].Type;
                        AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[i].Parameter = procedure[i].Parameter;
                        AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[i].Target = procedure[i].Target;
                    }

                    if (i <= pSelectedIndex) continue;

                    AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[i].Type = procedure[i - 1].Type;
                    AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[i].Parameter = procedure[i - 1].Parameter;
                    AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[i].Target = procedure[i - 1].Target;
                }

                AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Type = comboBox_Proc.SelectedIndex;
                AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Parameter = pArray;

                // Jade Dynasty
                if (JDSelected) AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Target =
                    Convert.ToInt32(JDProcedureTarget(textBox_ParamTarget.Text));

                // Perfect World
                if (PWSelected) AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[pSelectedIndex].Target =
                    Convert.ToInt32(PWProcedureTarget(textBox_ParamTarget.Text));

                listBox_Procedure.Items.Clear();

                for (var j = 0;
                     j < AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure.Length; j++)
                    listBox_Procedure.Items.Add("[" + j.ToString(CultureInfo.InvariantCulture) + "] " +
                        JDProcedureExpression(AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[j],
                        AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Version));
            }
            comboBox_Proc.SelectedIndex = -1;
        }
        
        private void ButtonDelProcClick(object sender, EventArgs e)
        {
            if (AI == null)
            {
                MessageBox.Show(Resources.OpenAIPolicyFirst + Resources.DeleteAProcedure);
                return;
            }

            if (listBox_Procedure.SelectedIndex != -1)
            {
                var cSelectedIndex = listBox_Controller.SelectedIndex;
                var asSelectedIndex = listBox_ActionSet.SelectedIndex;
                var pSelectedIndex = listBox_Procedure.SelectedIndex;

                if (AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure.Length <= 1)
                {
                    MessageBox.Show(Resources.RetainProcedure);
                    return;
                }

                var procedures = AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure;
                var pCount = AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].ProcedureCount - 1;

                AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure = new Procedure[pCount];

                for (var i = 0; i < pCount; i++)
                {
                    AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[i] = new Procedure();
                    if (i < pSelectedIndex)
                    {
                        AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[i].Type = procedures[i].Type;
                        AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[i].Parameter = procedures[i].Parameter;
                        AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[i].Target = procedures[i].Target;
                    }

                    if (i < pSelectedIndex) continue;

                    AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[i].Type = procedures[i + 1].Type;
                    AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[i].Parameter = procedures[i + 1].Parameter;
                    AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[i].Target = procedures[i + 1].Target;
                }

                AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].ProcedureCount =
                    AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].ProcedureCount - 1;

                listBox_Procedure.Items.Clear();

                for (var j = 0;
                     j < AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure.Length; j++)
                    listBox_Procedure.Items.Add("[" + j.ToString(CultureInfo.InvariantCulture) + "] " +
                        JDProcedureExpression(AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Procedure[j],
                        AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Version));
            }

            comboBox_Proc.SelectedIndex = -1;
        }

        private void ButtonEditProcClick(object sender, EventArgs e)
        {
            if (AI == null)
            {
                MessageBox.Show(Resources.OpenAIPolicyFirst + Resources.EditAProcedure);
                return;
            }

            if (listBox_Procedure.SelectedIndex == -1) return;

            var cSelectedIndex = listBox_Controller.SelectedIndex;
            var asSselectedIndex = listBox_ActionSet.SelectedIndex;
            var pSelectedIndex = listBox_Procedure.SelectedIndex;

            // Jade dynasty
            if (JDSelected) AI.ActionController[cSelectedIndex].ActionSet[asSselectedIndex].Procedure[pSelectedIndex].Parameter =
                JDGetParameters(AI.ActionController[cSelectedIndex].ActionSet[asSselectedIndex].Procedure[pSelectedIndex].Type,
                AI.ActionController[cSelectedIndex].ActionSet[asSselectedIndex].Version);

            // Perfect World
            if (PWSelected) AI.ActionController[cSelectedIndex].ActionSet[asSselectedIndex].Procedure[pSelectedIndex].Parameter =
                PWGetParameters(AI.ActionController[cSelectedIndex].ActionSet[asSselectedIndex].Procedure[pSelectedIndex].Type);

            listBox_Procedure.Items.Clear();

            for (var i = 0; i < AI.ActionController[cSelectedIndex].ActionSet[asSselectedIndex].Procedure.Length; i++)
            {
                var num = i;

                // Jade Dynasty
                if (JDSelected) listBox_Procedure.Items.Add("[" + num.ToString(CultureInfo.InvariantCulture) + "] " +
                    JDProcedureExpression(AI.ActionController[cSelectedIndex].ActionSet[asSselectedIndex].Procedure[i],
                    AI.ActionController[cSelectedIndex].ActionSet[asSselectedIndex].Version));

                // Perfect World
                if (PWSelected) listBox_Procedure.Items.Add("[" + num.ToString(CultureInfo.InvariantCulture) + "] " +
                    PWProcedureExpression(AI.ActionController[cSelectedIndex].ActionSet[asSselectedIndex].Procedure[i]));
            }
        }

        private void ButtonEditSaveClick(object sender, EventArgs e)
        {
            if (AI == null)
            {
                MessageBox.Show(Resources.OpenAIPolicyFirst + Resources.EditAnExpression);
                return;
            }
            if (listBox_ActionSet.SelectedIndex < 0) return;

            if (textBox_Condition.Text == "")
            {
                MessageBox.Show(Resources.NoExpressionEntered);
                return;
            }

            var cSelectedIndex = listBox_Controller.SelectedIndex;
            var asSelectedIndex = listBox_ActionSet.SelectedIndex;
            var text = textBox_Condition.Text;

            // Jade Dynasty
            if (JDSelected)
            {
                text = text.Replace(" ", "");
                text = text.Replace(Resources.Is_Timer_Ticking, "a");  // Is_Timer_Ticking[0]
                text = text.Replace(Resources.Is_HP_Less, "b");        // Is_HP_Less[0.00]
                text = text.Replace(Resources.Is_Combat_Started, "c"); // Is_Combat_Started[]
                text = text.Replace(Resources.Randomize, "d");         // Randomize[0.00]
                text = text.Replace(Resources.Is_Target_Killed, "e");  // Is_Target_Killed[]
                text = text.Replace("||", "f");                        // OR
                text = text.Replace("&&", "g");                        // AND
                text = text.Replace(Resources.Is_Dead, "h");           // Is_Dead[]
                text = text.Replace(Resources.Path_To, "i");           // Path_To[0]
                text = text.Replace(Resources.More_Than, "j");         // More_Than[0]
                text = text.Replace(Resources.Distance_To, "k");       // Distance_To[0.00]
                text = text.Replace(Resources.Unknown12, "l");         // Unknown12[]
                text = text.Replace(Resources.Unknown13, "m");         // Unknown13[]
                text = text.Replace(Resources.Unknown14, "n");         // Unknown14[]
                text = text.Replace(Resources.Unknown15, "o");         // Unknown15[]
                text = text.Replace(Resources.Public_Counter, "q");    // Public_Counter[0]
                text = text.Replace(Resources.Value, "p");             // Value[0]
                text = text.Replace(Resources.Rank, "r");              // Rank[0]
                text = text.Replace(Resources.Remove_Mob, "s");        // Remove_Mob[]
                text = text.Replace(Resources.Cast_Skill, "t");        // Cast_Skill[0]
                text = text.Replace("【", "[");
                text = text.Replace("】", "]");
                text = text.Replace("！", "!");
                text = text.Replace("１", "1");
                text = text.Replace("２", "2");
                text = text.Replace("３", "3");
                text = text.Replace("４", "4");
                text = text.Replace("５", "5");
                text = text.Replace("６", "6");
                text = text.Replace("７", "7");
                text = text.Replace("８", "8");
                text = text.Replace("９", "9");
                text = text.Replace("０", "0");
                text = text.Replace("。", ".");
                text = text.Replace("（", "(");
                text = text.Replace("）", ")");
                text = text.Replace("[", "");
                text = text.Replace("]", "");
                text = text.Replace("，", ",");
            }

            // Perfect World
            if (PWSelected)
            {
                text = text.Replace(" ", "");
                text = text.Replace(Resources.Is_Timer_Ticking, "a");  // Is_Timer_Ticking[0]
                text = text.Replace(Resources.Is_HP_Less, "b");        // Is_HP_Less[0.00]
                text = text.Replace(Resources.Is_Combat_Started, "c"); // Is_Combat_Started[]
                text = text.Replace(Resources.Randomize, "d");         // Randomize[0.00]
                text = text.Replace(Resources.Is_Target_Killed, "e");  // Is_Target_Killed[]
                text = text.Replace("||", "f");                        // OR
                text = text.Replace("&&", "g");                        // AND
                text = text.Replace(Resources.Is_Dead, "h");           // Is_Dead[]
                text = text.Replace(Resources.Public_Counter, "i");    // Public_Counter[0]
                text = text.Replace("Value", "j");                     // Value[0]
                text = text.Replace(Resources.Is_Event, "k");          // Is_Event[]
                text = text.Replace("【", "[");
                text = text.Replace("】", "]");
                text = text.Replace("！", "!");
                text = text.Replace("１", "1");
                text = text.Replace("２", "2");
                text = text.Replace("３", "3");
                text = text.Replace("４", "4");
                text = text.Replace("５", "5");
                text = text.Replace("６", "6");
                text = text.Replace("７", "7");
                text = text.Replace("８", "8");
                text = text.Replace("９", "9");
                text = text.Replace("０", "0");
                text = text.Replace("。", ".");
                text = text.Replace("（", "(");
                text = text.Replace("）", ")");
                text = text.Replace("[", "");
                text = text.Replace("]", "");
                text = text.Replace("，", ",");
            }

            if (toolStripComboBox_Decimal.SelectedIndex == 1)
                text = text.Replace(",", ".");

            if (!Common.IsMatch(text))
                MessageBox.Show(Resources.ExpressionNoMatch);
            else
            {
                for (var i = 0; i < text.Length; i++)
                {
                    var expr = text.Substring(i, 1);

                    // Jade Dynasty
                    if (JDSelected)
                        if (expr == "(" || expr == ")" || expr == "." || Common.IsNumber(expr) || Common.JDIDOper(expr) >= 0)
                            continue;

                    // Perfect World
                    if (PWSelected)
                        if (expr == "(" || expr == ")" || expr == "." || Common.IsNumber(expr) || Common.PWIDOper(expr) >= 0)
                            continue;

                    MessageBox.Show(Resources.UnableResolveSymbol + expr + Resources.SingleQuote);
                    return;
                }

                // Jade Dynasty
                if (JDSelected)
                {
                    AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Condition = JDGetCondition(text);
                    AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Condition =
                        JDFixCondition(AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Condition);
                }

                // Perfect World
                if (PWSelected)
                    AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Condition = PWGetCondition(text);

                textBox_Condition.Clear();

                // Jade Dynasty
                if (JDSelected) textBox_Condition.Text = JDConditionExpression(AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Condition);
                // Perfect World
                if (PWSelected) textBox_Condition.Text = PWConditionExpression(AI.ActionController[cSelectedIndex].ActionSet[asSelectedIndex].Condition);
            }

        }

        private void ButtonExpCalcClick(object sender, EventArgs e)
        {
            panel_ExpCalc.Visible = true;
        }

        private void Button0Click(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.ZERO;
            Encode += Resources.ZERO;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void Button1Click(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.ONE;
            Encode += Resources.ONE;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void Button2Click(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.TWO;
            Encode += Resources.TWO;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void Button3Click(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.THREE;
            Encode += Resources.THREE;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void Button4Click(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.FOUR;
            Encode += Resources.FOUR;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void Button5Click(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.FIVE;
            Encode += Resources.FIVE;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void Button6Click(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.SIX;
            Encode += Resources.SIX;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void Button7Click(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.SEVEN;
            Encode += Resources.SEVEN;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void Button8Click(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.EIGHT;
            Encode += Resources.EIGHT;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void Button9Click(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.NINE;
            Encode += Resources.NINE;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void ButtonPointClick(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.PERIOD;
            Encode += Resources.PERIOD;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void ButtonEqualsClick(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.EQUAL;
            Encode += Resources.EQUAL;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void ButtonLessClick(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.LESS;
            Encode += Resources.LESS;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void ButtonGreaterClick(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.GREATER;
            Encode += Resources.GREATER;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void ButtonLBracketClick(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.LBRACKET;
            Encode += Resources.LBRACKET;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void ButtonRBracketClick(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.RBRACKET;
            Encode += Resources.RBRACKET;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void ButtonLParenClick(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.LPAREN;
            Encode += Resources.LPAREN;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void ButtonRParenClick(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.RPAREN;
            Encode += Resources.RPAREN;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void ButtonNOTClick(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.NOT;
            Encode += Resources.NOT;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void ButtonORClick(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.OR;
            Encode += Resources.OR;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void ButtonANDClick(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.AND;
            Encode += Resources.AND;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void ButtonCommaClick(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.COMMA;
            Encode += Resources.COMMA;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void ButtonPlusClick(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.PLUS;
            Encode += Resources.PLUS;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void ButtonMinusClick(object sender, EventArgs e)
        {
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            textBox_Exp.Text += Resources.MINUS;
            Encode += Resources.MINUS;

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void ButtonCalcClearClick(object sender, EventArgs e)
        {
            if (textBox_Exp.Text == "") return;

            while (undoBuffer.CanUndo)
            {
                undoBuffer.Undo();
                encodeBuffer.Undo();
            }

            textBox_Exp.Text = undoBuffer.Value;
            Encode = encodeBuffer.Value;

            label_HintText.Text = "";
            label_Hint.Visible = false;
            label_ExampleText.Text = "";
            label_Example.Visible = false;
        }

        private void ButtonCalcUndoClick(object sender, EventArgs e)
        {
            label_HintText.Text = "";
            label_Hint.Visible = false;
            label_ExampleText.Text = "";
            label_Example.Visible = false;

            if (undoBuffer.CanUndo)
            {
                undoBuffer.Undo();
                encodeBuffer.Undo();
            }

            textBox_Exp.Text = undoBuffer.Value;
            Encode = encodeBuffer.Value;
        }

        private void ButtonCalcRedoClick(object sender, EventArgs e)
        {
            label_HintText.Text = "";
            label_Hint.Visible = false;
            label_ExampleText.Text = "";
            label_Example.Visible = false;

            if (undoBuffer.CanRedo)
            {
                undoBuffer.Redo();
                encodeBuffer.Redo();
            }

            textBox_Exp.Text = undoBuffer.Value;
            Encode = encodeBuffer.Value;
        }

        private void ButtonCalcOKClick(object sender, EventArgs e)
        {
            // Clear Hint/Example
            label_HintText.Text = "";
            label_Hint.Visible = false;
            label_ExampleText.Text = "";
            label_Example.Visible = false;

            // Transfer Encoded to textbox
            textBox_Condition.Text = Encode;
            panel_ExpCalc.Visible = false;

            // Auto-Click Edit/Save Button
            ButtonEditSaveClick(sender, e);
        }

        private void ButtonCalcCancelClick(object sender, EventArgs e)
        {
            panel_ExpCalc.Visible = false;
        }

        private void ComboBoxExpSelectedIndexChanged(object sender, EventArgs e)
        {
            // Clear Hint/Example
            label_HintText.Text = "";
            label_Hint.Visible = false;
            label_ExampleText.Text = "";
            label_Example.Visible = false;

            // Set undo buffer
            undoBuffer.SaveState();
            encodeBuffer.SaveState();

            // Set condition in textbox
            textBox_Exp.Text += comboBox_Exp.Text;

            // Is_Timer_Ticking[x]
            if (comboBox_Exp.Text == Resources.Is_Timer_Ticking)
            {
                // Give Hint/Example
                label_Hint.Visible = true;
                label_HintText.Text = Resources.ITT1P;
                label_Example.Visible = true;
                label_ExampleText.Text = Resources.ITT1PEx;
                // Encode
                Encode += "a";
            }

            // Is_HP_Less[x.xx]
            if (comboBox_Exp.Text == Resources.Is_HP_Less)
            {
                // Give Hint/Example
                label_Hint.Visible = true;
                label_HintText.Text = Resources.IHPL1P;
                label_Example.Visible = true;
                switch (toolStripComboBox_Decimal.SelectedIndex)
                {
                    case 0:
                        label_ExampleText.Text = Resources.IHPL1PExPeriod;
                        break;
                    case 1:
                        label_ExampleText.Text = Resources.IHPL1PComma;
                        break;
                }
                // Encode
                Encode += "b";
            }

            // Is_Combat_Started[]
            if (comboBox_Exp.Text == Resources.Is_Combat_Started)
            {
                // Give Hint/Example
                label_Hint.Visible = true;
                label_HintText.Text = Resources.ICS0P;
                label_Example.Visible = true;
                label_ExampleText.Text = Resources.ICS0PEx;
                // Encode
                Encode += "c[]";
            }

            // Randomize[x.xx]
            if (comboBox_Exp.Text == Resources.Randomize)
            {
                // Give Hint/Example
                label_Hint.Visible = true;
                label_HintText.Text = Resources.RND1P;
                label_Example.Visible = true;
                label_ExampleText.Text = Resources.RND1PEx;
                // Encode
                Encode += "d";
            }
            // Is_Target_Dead[]
            if (comboBox_Exp.Text == Resources.Is_Target_Killed)
            {
                // Give Hint/Example
                label_Hint.Visible = true;
                label_HintText.Text = Resources.ITK0P;
                label_Example.Visible = true;
                label_ExampleText.Text = Resources.ITK0PEx;
                // Encode
                Encode += "e[]";
            }

            // Is_Dead[]
            if (comboBox_Exp.Text == Resources.Is_Dead)
            {
                // Give Hint/Example
                label_Hint.Visible = true;
                label_HintText.Text = Resources.ID0P;
                label_Example.Visible = true;
                label_ExampleText.Text = Resources.ID0PEx;
                // Encode
                Encode += "h[]";
            }

            // Perfect World - Public_Counter[x]
            if (PWSelected)
            {
                if (comboBox_Exp.Text == Resources.Public_Counter)
                {
                    // Give Hint/Example
                    label_Hint.Visible = true;
                    label_HintText.Text = Resources.PC1P;
                    label_Example.Visible = true;
                    label_ExampleText.Text = Resources.PC1PEx;
                    // Encode
                    Encode += "i";
                }

                // Perfect World - Value[0]
                if (comboBox_Exp.Text == Resources.Value)
                {
                    // Give Hint/Example
                    label_Hint.Visible = true;
                    label_HintText.Text = Resources.Val1P;
                    label_Example.Visible = true;
                    label_ExampleText.Text = Resources.Val1PEx;
                    // Encode
                    Encode += "j";
                }

                // Perfect World - Is_Event[]
                if (comboBox_Exp.Text == Resources.Is_Event)
                {
                    // Give Hint/Example
                    label_Hint.Visible = true;
                    label_HintText.Text = Resources.IsEv0P;
                    label_Example.Visible = true;
                    label_ExampleText.Text = Resources.IsEv0PEx;
                    // Encode
                    Encode += "k[]";
                }
            } // End Perfect World

            // Jade Dynasty
            if (JDSelected)
            {
                // Jade Dynasty - Path_To[0]
                if (comboBox_Exp.Text == Resources.Path_To)
                {
                    // Give Hint/Example
                    label_Hint.Visible = true;
                    label_HintText.Text = Resources.PT1P;
                    label_Example.Visible = true;
                    label_ExampleText.Text = Resources.PT1PEx;
                    // Encode
                    Encode += "i";
                }

                // Jade Dynasty - More_Than[0]
                if (comboBox_Exp.Text == Resources.More_Than)
                {
                    // Give Hint/Example
                    label_Hint.Visible = true;
                    label_HintText.Text = Resources.MT1P;
                    label_Example.Visible = true;
                    label_ExampleText.Text = Resources.MT1PEx;
                    // Encode
                    Encode += "j";
                }

                // Jade Dynasty - Distance_To[0.00]
                if (comboBox_Exp.Text == Resources.Distance_To)
                {
                    // Give Hint/Example
                    label_Hint.Visible = true;
                    label_HintText.Text = Resources.DT1P;
                    label_Example.Visible = true;
                    label_ExampleText.Text = Resources.DT1PEx;
                    // Encode
                    Encode += "k";
                }

                // Jade Dynasty - Unknown12[]
                if (comboBox_Exp.Text == Resources.Unknown12)
                {
                    // Give Hint/Example
                    label_Hint.Visible = true;
                    label_HintText.Text = Resources.U120P;
                    label_Example.Visible = true;
                    label_ExampleText.Text = Resources.U120PEx;
                    // Encode
                    Encode += "l[]";
                }

                // Jade Dynasty - Unknown13[]
                if (comboBox_Exp.Text == Resources.Unknown13)
                {
                    // Give Hint/Example
                    label_Hint.Visible = true;
                    label_HintText.Text = Resources.U130P;
                    label_Example.Visible = true;
                    label_ExampleText.Text = Resources.U130PEx;
                    // Encode
                    Encode += "m[]";
                }

                // Jade Dynasty - Unknown14[]
                if (comboBox_Exp.Text == Resources.Unknown14)
                {
                    // Give Hint/Example
                    label_Hint.Visible = true;
                    label_HintText.Text = Resources.U140P;
                    label_Example.Visible = true;
                    label_ExampleText.Text = Resources.U140PEx;
                    // Encode
                    Encode += "n[]";
                }

                // Jade Dynasty - Unknown15[]
                if (comboBox_Exp.Text == Resources.Unknown15)
                {
                    // Give Hint/Example
                    label_Hint.Visible = true;
                    label_HintText.Text = Resources.U150P;
                    label_Example.Visible = true;
                    label_ExampleText.Text = Resources.U150PEx;
                    // Encode
                    Encode += "o[]";
                }

                // Jade Dynasty - Public_Counter[0]
                if (comboBox_Exp.Text == Resources.Public_Counter)
                {
                    // Give Hint/Example
                    label_Hint.Visible = true;
                    label_HintText.Text = Resources.PC1P;
                    label_Example.Visible = true;
                    label_ExampleText.Text = Resources.PC1PEx;
                    // Encode
                    Encode += "q";
                }

                // Jade Dynasty - Value[0]
                if (comboBox_Exp.Text == Resources.Value)
                {
                    // Give Hint/Example
                    label_Hint.Visible = true;
                    label_HintText.Text = Resources.Val1P;
                    label_Example.Visible = true;
                    label_ExampleText.Text = Resources.Val1PEx;
                    // Encode
                    Encode += "p";
                }

                // Jade Dynasty - Rank[0]
                if (comboBox_Exp.Text == Resources.Rank)
                {
                    // Give Hint/Example
                    label_Hint.Visible = true;
                    label_HintText.Text = Resources.Rnk1P;
                    label_Example.Visible = true;
                    label_ExampleText.Text = Resources.Rnk1PEx;
                    // Encode
                    Encode += "r";
                }

                // Jade Dynasty - Remove_Mob[0]
                if (comboBox_Exp.Text == Resources.Remove_Mob)
                {
                    // Give Hint/Example
                    label_Hint.Visible = true;
                    label_HintText.Text = Resources.RM0P;
                    label_Example.Visible = true;
                    label_ExampleText.Text = Resources.RM0PEx;
                    // Encode
                    Encode += "s[]";
                }

                // Jade Dynasty - Cast_Skill[0]
                if (comboBox_Exp.Text == Resources.Cast_Skill)
                {
                    // Give Hint/Example
                    label_Hint.Visible = true;
                    label_HintText.Text = Resources.CS1P;
                    label_Example.Visible = true;
                    label_ExampleText.Text = Resources.CS1PEx;
                    // Encode
                    Encode += "t";
                }
            }

            undoBuffer.Value = textBox_Exp.Text;
            encodeBuffer.Value = Encode;
        }

        private void ButtonMsgOKClick(object sender, EventArgs e)
        {
            panel_MsgHelper.Visible = false;
            var length = (textBox_BMHMsg.TextLength * 2) + 2;
            textBox_Param1.Text = length.ToString(CultureInfo.InvariantCulture);
            textBox_Param2.Text = textBox_BMHMsg.Text;
        }

        private void ButtonMsgCancelClick(object sender, EventArgs e)
        {
            panel_MsgHelper.Visible = false;
        }

        private void ButtonTHOKClick(object sender, EventArgs e)
        {
            panel_TargetHelper.Visible = false;
            textBox_ParamTarget.Text = comboBox_THTargets.Text;
        }

        private void ButtonTHCancelClick(object sender, EventArgs e)
        {
            panel_TargetHelper.Visible = false;
        }

        private void ComboBoxCatSelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBox_Cat.SelectedIndex <= -1) return;

            comboBox_SubCat.Items.Clear();

            // Conditions
            if (comboBox_Cat.SelectedIndex == 1)
            {
                comboBox_SubCat.Items.Add("All");
                comboBox_SubCat.SelectedIndex = 0;
                return;
            }

            // AI Control Link
            if (comboBox_Cat.SelectedIndex != 0) return;

            var aiControlLink = new object[]
            {
                "Task",
                "Element NPC"
            };

            comboBox_SubCat.Items.AddRange(aiControlLink);
            comboBox_SubCat.SelectedIndex = 0;

            // Jade Dynasty Procedures
            if (JDSelected)
            {
                if (comboBox_Cat.SelectedIndex == 2)
                {
                    var procs = new object[]
                    {
                        "Attack",
                        "Cast_Skill",
                        "Broadcast_Message",
                        "Reset_Aggro",
                        "Execute_ActionSet",
                        "Disable_ActionSet",
                        "Enable_ActionSet",
                        "Create_Timer",
                        "Remove_Timer",
                        "Flee",
                        "Be_Taunted",
                        "Fade_Target",
                        "Fade_Aggro",
                        "Break",
                        "NPC_Generator",
                        "Summon_Mob",
                        "Unknown16",
                        "Set_Path",
                        "Disappear",
                        "N/A",
                        "N/A",
                        "Respawn",
                        "Set_Value",
                        "Add_Value",
                        "N/A",
                        "Set_Mob_Attribute",
                        "Drop_WarSoul"
                    };

                    comboBox_SubCat.Items.AddRange(procs);
                    comboBox_SubCat.SelectedIndex = 0;
                }
                else return;
            }


            // Perfect World Procedures
            if (PWSelected)
            {
                if (comboBox_Cat.SelectedIndex == 2)
                {
                    var procs = new object[]
                    {
                        "Attack",
                        "Cast_Skill",
                        "Broadcast_Message",
                        "Reset_Aggro",
                        "Execute_ActionSet",
                        "Disable_ActionSet",
                        "Enable_ActionSet",
                        "Create_Timer",
                        "Remove_Timer",
                        "Flee",
                        "Be_Taunted",
                        "Fade_Target",
                        "Fade_Aggro",
                        "Break",
                        "NPC_Generator",
                        "Initialize_Public_Counter",
                        "Increment_Public_Counter",
                        "Player_Aimed_NPC_Spawn",
                        "Change_Path",
                        "Play_Action"
                    };

                    comboBox_SubCat.Items.AddRange(procs);
                    comboBox_SubCat.SelectedIndex = 0;
                }
                else return;
            }

            // Targets
            if (comboBox_Cat.SelectedIndex != 3) return;
            var trgt = new object[]
            {
                "AGGRO_FIRST",
                "AGGRO_SECOND",
                "AGGRO_SECOND_RAND",
                "MOST_HP",
                "MOST_MP",
                "LEAST_HP",
                "CLASS_COMBO",
                "SELF"
            };

            comboBox_SubCat.Items.AddRange(trgt);
            comboBox_SubCat.SelectedIndex = 0;
        }

        private void ButtonAIFindNextClick(object sender, EventArgs e)
        {
            if (AI == null)
            {
                MessageBox.Show(Resources.OpenAIPolicyFirst + Resources.SearchAFile);
                return;
            }

            if (AI != null && comboBox_Cat.SelectedIndex > -1)
            {
                var i = 0;
                var j = 0;
                var k = 0;

                if (listBox_Controller.SelectedIndex > -1) i = listBox_Controller.SelectedIndex;

                if (listBox_ActionSet.SelectedIndex > -1)
                {
                    j = listBox_ActionSet.SelectedIndex;

                    if (comboBox_Cat.SelectedItem.ToString() == "Conditions") j++;
                }

                if (listBox_Procedure.SelectedIndex > -1)
                {
                    k = listBox_Procedure.SelectedIndex;
                    if (comboBox_Cat.SelectedItem.ToString() == "Procedures") k++;
                }

                while (i < AI.ActionController.Length)
                {
                    if (comboBox_Cat.SelectedItem.ToString() == "AI Control Link" &&
                        comboBox_SubCat.SelectedIndex > -1 && textBox_Pattern.Text != "")
                    {
                        var num = 0;

                        if (comboBox_SubCat.SelectedItem.ToString() == "Task")
                        {
                            MessageBox.Show(Resources.TaskAINotFound);
                            return;
                        }

                        if (comboBox_SubCat.SelectedItem.ToString() == "Element NPC")
                            num = Convert.ToInt32(textBox_Pattern.Text);

                        if (AI.ActionController[i].ID == num)
                        {
                            listBox_Controller.SelectedIndex = i;
                            return;
                        }
                    }

                    while (j < AI.ActionController[i].ActionSet.Length)
                    {
                        // Jade Dynasty
                        if (JDSelected)
                            if (comboBox_Cat.SelectedItem.ToString() == "Conditions" && textBox_Pattern.Text != "" &&
                                JDConditionExpression(AI.ActionController[i].ActionSet[j].Condition).Contains(
                                    textBox_Pattern.Text))
                            {
                                listBox_Controller.SelectedIndex = i;
                                listBox_ActionSet.SelectedIndex = j;
                                return;
                            }

                        // Perfect World
                        if (PWSelected)
                            if (comboBox_Cat.SelectedItem.ToString() == "Conditions" && textBox_Pattern.Text != "" &&
                                PWConditionExpression(AI.ActionController[i].ActionSet[j].Condition).Contains(
                                    textBox_Pattern.Text))
                            {
                                listBox_Controller.SelectedIndex = i;
                                listBox_ActionSet.SelectedIndex = j;
                                return;
                            }

                        if (comboBox_Cat.SelectedItem.ToString() == "Procedures" && comboBox_SubCat.SelectedIndex > -1)
                        {
                            while (k < AI.ActionController[i].ActionSet[j].Procedure.Length)
                            {
                                // Jade Dynasty
                                if (JDSelected)
                                    if (AI.ActionController[i].ActionSet[j].Procedure[k].Type == comboBox_SubCat.SelectedIndex &&
                                        (textBox_Pattern.Text == "" || JDProcedureExpression(AI.ActionController[i].ActionSet[j].Procedure[k],
                                        AI.ActionController[i].ActionSet[j].Version).Contains(textBox_Pattern.Text)))
                                    {
                                        listBox_Controller.SelectedIndex = i;
                                        listBox_ActionSet.SelectedIndex = j;
                                        listBox_Procedure.SelectedIndex = k;
                                        return;
                                    }

                                // Perfect World
                                if (PWSelected)
                                    if (AI.ActionController[i].ActionSet[j].Procedure[k].Type == comboBox_SubCat.SelectedIndex &&
                                        (textBox_Pattern.Text == "" || PWProcedureExpression(AI.ActionController[i].ActionSet[j].Procedure[k]).
                                        Contains(textBox_Pattern.Text)))
                                    {
                                        listBox_Controller.SelectedIndex = i;
                                        listBox_ActionSet.SelectedIndex = j;
                                        listBox_Procedure.SelectedIndex = k;
                                        return;
                                    }

                                k++;
                            }

                            k = 0;
                        }
                        if (comboBox_Cat.SelectedItem.ToString() == "Targets" && comboBox_SubCat.SelectedIndex > -1)
                        {
                            while (k < AI.ActionController[i].ActionSet[j].Procedure.Length)
                            {
                                // Jade Dynasty
                                if (JDSelected)
                                    if (AI.ActionController[i].ActionSet[j].Procedure[k].Target == comboBox_SubCat.SelectedIndex &&
                                        (textBox_Pattern.Text == "" || JDProcedureExpression(AI.ActionController[i].ActionSet[j].Procedure[k],
                                        AI.ActionController[i].ActionSet[j].Version).Contains(textBox_Pattern.Text)))
                                    {
                                        listBox_Controller.SelectedIndex = i;
                                        listBox_ActionSet.SelectedIndex = j;
                                        listBox_Procedure.SelectedIndex = k;
                                        return;
                                    }

                                // Perfect World
                                if (PWSelected)
                                    if (AI.ActionController[i].ActionSet[j].Procedure[k].Target == comboBox_SubCat.SelectedIndex &&
                                        (textBox_Pattern.Text == "" || PWProcedureExpression(AI.ActionController[i].ActionSet[j].Procedure[k]).
                                        Contains(textBox_Pattern.Text)))
                                    {
                                        listBox_Controller.SelectedIndex = i;
                                        listBox_ActionSet.SelectedIndex = j;
                                        listBox_Procedure.SelectedIndex = k;
                                        return;
                                    }
                                k++;
                            }
                            k = 0;
                        }
                        j++;
                    }
                    j = 0;
                    i++;
                }
            }
            MessageBox.Show(Resources.SearchNoResults);
        }
        
    }
}
